mirror of
https://github.com/ansible-collections/hetzner.hcloud
synced 2024-11-10 06:34:13 +00:00
deps: update dependency hcloud to v1.27.1 (#290)
* deps: update dependency hcloud to v1.27.1 * chore: update vendored files --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: jo <ljonas@riseup.net>
This commit is contained in:
parent
a035b7d4c2
commit
ff539800aa
65 changed files with 2489 additions and 1684 deletions
|
@ -1,2 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from ._client import Client # noqa
|
||||
from ._exceptions import APIException, HCloudException # noqa
|
||||
|
|
65
plugins/module_utils/vendor/hcloud/_client.py
vendored
65
plugins/module_utils/vendor/hcloud/_client.py
vendored
|
@ -1,5 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import Optional, Union
|
||||
from typing import NoReturn
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
@ -8,23 +10,23 @@ except ImportError:
|
|||
|
||||
from ._version import VERSION
|
||||
from ._exceptions import APIException
|
||||
from .actions.client import ActionsClient
|
||||
from .certificates.client import CertificatesClient
|
||||
from .datacenters.client import DatacentersClient
|
||||
from .firewalls.client import FirewallsClient
|
||||
from .floating_ips.client import FloatingIPsClient
|
||||
from .images.client import ImagesClient
|
||||
from .isos.client import IsosClient
|
||||
from .load_balancer_types.client import LoadBalancerTypesClient
|
||||
from .load_balancers.client import LoadBalancersClient
|
||||
from .locations.client import LocationsClient
|
||||
from .networks.client import NetworksClient
|
||||
from .placement_groups.client import PlacementGroupsClient
|
||||
from .primary_ips.client import PrimaryIPsClient
|
||||
from .server_types.client import ServerTypesClient
|
||||
from .servers.client import ServersClient
|
||||
from .ssh_keys.client import SSHKeysClient
|
||||
from .volumes.client import VolumesClient
|
||||
from .actions import ActionsClient
|
||||
from .certificates import CertificatesClient
|
||||
from .datacenters import DatacentersClient
|
||||
from .firewalls import FirewallsClient
|
||||
from .floating_ips import FloatingIPsClient
|
||||
from .images import ImagesClient
|
||||
from .isos import IsosClient
|
||||
from .load_balancer_types import LoadBalancerTypesClient
|
||||
from .load_balancers import LoadBalancersClient
|
||||
from .locations import LocationsClient
|
||||
from .networks import NetworksClient
|
||||
from .placement_groups import PlacementGroupsClient
|
||||
from .primary_ips import PrimaryIPsClient
|
||||
from .server_types import ServerTypesClient
|
||||
from .servers import ServersClient
|
||||
from .ssh_keys import SSHKeysClient
|
||||
from .volumes import VolumesClient
|
||||
|
||||
|
||||
class Client:
|
||||
|
@ -38,9 +40,10 @@ class Client:
|
|||
self,
|
||||
token: str,
|
||||
api_endpoint: str = "https://api.hetzner.cloud/v1",
|
||||
application_name: Optional[str] = None,
|
||||
application_version: Optional[str] = None,
|
||||
application_name: str | None = None,
|
||||
application_version: str | None = None,
|
||||
poll_interval: int = 1,
|
||||
timeout: float | tuple[float, float] | None = None,
|
||||
):
|
||||
"""Create an new Client instance
|
||||
|
||||
|
@ -49,12 +52,14 @@ class Client:
|
|||
:param application_name: Your application name
|
||||
:param application_version: Your application _version
|
||||
:param poll_interval: Interval for polling information from Hetzner Cloud API in seconds
|
||||
:param timeout: Requests timeout in seconds
|
||||
"""
|
||||
self.token = token
|
||||
self._api_endpoint = api_endpoint
|
||||
self._application_name = application_name
|
||||
self._application_version = application_version
|
||||
self._requests_session = requests.Session()
|
||||
self._requests_timeout = timeout
|
||||
self.poll_interval = poll_interval
|
||||
|
||||
self.datacenters = DatacentersClient(self)
|
||||
|
@ -169,38 +174,42 @@ class Client:
|
|||
}
|
||||
return headers
|
||||
|
||||
def _raise_exception_from_response(self, response):
|
||||
def _raise_exception_from_response(self, response) -> NoReturn:
|
||||
raise APIException(
|
||||
code=response.status_code,
|
||||
message=response.reason,
|
||||
details={"content": response.content},
|
||||
)
|
||||
|
||||
def _raise_exception_from_content(self, content: dict):
|
||||
def _raise_exception_from_content(self, content: dict) -> NoReturn:
|
||||
raise APIException(
|
||||
code=content["error"]["code"],
|
||||
message=content["error"]["message"],
|
||||
details=content["error"]["details"],
|
||||
)
|
||||
|
||||
def request(
|
||||
def request( # type: ignore[no-untyped-def]
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
tries: int = 1,
|
||||
**kwargs,
|
||||
) -> Union[bytes, dict]:
|
||||
) -> dict:
|
||||
"""Perform a request to the Hetzner Cloud API, wrapper around requests.request
|
||||
|
||||
:param method: HTTP Method to perform the Request
|
||||
:param url: URL of the Endpoint
|
||||
:param tries: Tries of the request (used internally, should not be set by the user)
|
||||
:param timeout: Requests timeout in seconds
|
||||
:return: Response
|
||||
"""
|
||||
timeout = kwargs.pop("timeout", self._requests_timeout)
|
||||
|
||||
response = self._requests_session.request(
|
||||
method=method,
|
||||
url=self._api_endpoint + url,
|
||||
headers=self._get_headers(),
|
||||
timeout=timeout,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
@ -213,13 +222,15 @@ class Client:
|
|||
|
||||
if not response.ok:
|
||||
if content:
|
||||
assert isinstance(content, dict)
|
||||
if content["error"]["code"] == "rate_limit_exceeded" and tries < 5:
|
||||
time.sleep(tries * self._retry_wait_time)
|
||||
tries = tries + 1
|
||||
return self.request(method, url, tries, **kwargs)
|
||||
else:
|
||||
self._raise_exception_from_content(content)
|
||||
|
||||
self._raise_exception_from_content(content)
|
||||
else:
|
||||
self._raise_exception_from_response(response)
|
||||
|
||||
return content
|
||||
# TODO: return an empty dict instead of an empty string when content == "".
|
||||
return content # type: ignore[return-value]
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class HCloudException(Exception):
|
||||
"""There was an error while using the hcloud library"""
|
||||
|
||||
|
@ -5,7 +10,7 @@ class HCloudException(Exception):
|
|||
class APIException(HCloudException):
|
||||
"""There was an error while performing an API Request"""
|
||||
|
||||
def __init__(self, code, message, details):
|
||||
def __init__(self, code: int | str, message: str, details: Any):
|
||||
super().__init__(message)
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
VERSION = "1.26.0" # x-release-please-version
|
||||
from __future__ import annotations
|
||||
|
||||
VERSION = "1.27.1" # x-release-please-version
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ActionsClient, ActionsPageResult, BoundAction # noqa: F401
|
||||
from .domain import ( # noqa: F401
|
||||
Action,
|
||||
ActionException,
|
||||
ActionFailedException,
|
||||
ActionTimeoutException,
|
||||
)
|
|
@ -1,13 +1,21 @@
|
|||
import time
|
||||
from __future__ import annotations
|
||||
|
||||
from ..core.client import BoundModelBase, ClientEntityBase
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import Action, ActionFailedException, ActionTimeoutException
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundAction(BoundModelBase):
|
||||
_client: ActionsClient
|
||||
|
||||
model = Action
|
||||
|
||||
def wait_until_finished(self, max_retries=100):
|
||||
def wait_until_finished(self, max_retries: int = 100) -> None:
|
||||
"""Wait until the specific action has status="finished" (set Client.poll_interval to specify a delay between checks)
|
||||
|
||||
:param max_retries: int
|
||||
|
@ -27,11 +35,15 @@ class BoundAction(BoundModelBase):
|
|||
raise ActionFailedException(action=self)
|
||||
|
||||
|
||||
class ActionsClient(ClientEntityBase):
|
||||
results_list_attribute_name = "actions"
|
||||
class ActionsPageResult(NamedTuple):
|
||||
actions: list[BoundAction]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundAction
|
||||
|
||||
class ActionsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundAction:
|
||||
"""Get a specific action by its ID.
|
||||
|
||||
:param id: int
|
||||
|
@ -43,12 +55,11 @@ class ActionsClient(ClientEntityBase):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
status=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundAction]]
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Get a list of actions from this account
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -61,7 +72,7 @@ class ActionsClient(ClientEntityBase):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -75,10 +86,13 @@ class ActionsClient(ClientEntityBase):
|
|||
actions = [
|
||||
BoundAction(self, action_data) for action_data in response["actions"]
|
||||
]
|
||||
return self._add_meta_to_result(actions, response)
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_all(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Get all actions of the account
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -87,4 +101,4 @@ class ActionsClient(ClientEntityBase):
|
|||
Specify how the results are sorted. Choices: `id` `command` `status` `progress` `started` `finished` . You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default)
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_all(status=status, sort=sort)
|
||||
return self._iter_pages(self.get_list, status=status, sort=sort)
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from .._exceptions import HCloudException
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .client import BoundAction
|
||||
|
||||
|
||||
class Action(BaseDomain):
|
||||
|
@ -40,14 +47,14 @@ class Action(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
command=None,
|
||||
status=None,
|
||||
progress=None,
|
||||
started=None,
|
||||
finished=None,
|
||||
resources=None,
|
||||
error=None,
|
||||
id: int,
|
||||
command: str | None = None,
|
||||
status: str | None = None,
|
||||
progress: int | None = None,
|
||||
started: str | None = None,
|
||||
finished: str | None = None,
|
||||
resources: list[dict] | None = None,
|
||||
error: dict | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.command = command
|
||||
|
@ -63,7 +70,8 @@ class Action(BaseDomain):
|
|||
class ActionException(HCloudException):
|
||||
"""A generic action exception"""
|
||||
|
||||
def __init__(self, action):
|
||||
def __init__(self, action: Action | BoundAction):
|
||||
assert self.__doc__ is not None
|
||||
message = self.__doc__
|
||||
if action.error is not None and "message" in action.error:
|
||||
message += f": {action.error['message']}"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundCertificate,
|
||||
CertificatesClient,
|
||||
CertificatesPageResult,
|
||||
)
|
||||
from .domain import ( # noqa: F401
|
||||
Certificate,
|
||||
CreateManagedCertificateResponse,
|
||||
ManagedCertificateError,
|
||||
ManagedCertificateStatus,
|
||||
)
|
|
@ -1,6 +1,9 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import (
|
||||
Certificate,
|
||||
CreateManagedCertificateResponse,
|
||||
|
@ -8,11 +11,16 @@ from .domain import (
|
|||
ManagedCertificateStatus,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundCertificate(BoundModelBase):
|
||||
_client: CertificatesClient
|
||||
|
||||
model = Certificate
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
def __init__(self, client: CertificatesClient, data: dict, complete: bool = True):
|
||||
status = data.get("status")
|
||||
if status is not None:
|
||||
error_data = status.get("error")
|
||||
|
@ -26,8 +34,13 @@ class BoundCertificate(BoundModelBase):
|
|||
)
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction, Meta]]
|
||||
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 action objects for a Certificate.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -42,8 +55,11 @@ class BoundCertificate(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Certificate.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -54,8 +70,11 @@ class BoundCertificate(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def update(self, name=None, labels=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]]) -> BoundCertificate
|
||||
def update(
|
||||
self,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundCertificate:
|
||||
"""Updates an certificate. You can update an certificate name and the certificate labels.
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -66,26 +85,28 @@ class BoundCertificate(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, name, labels)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a certificate.
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def retry_issuance(self):
|
||||
# type: () -> BoundAction
|
||||
def retry_issuance(self) -> BoundAction:
|
||||
"""Retry a failed Certificate issuance or renewal.
|
||||
:return: BoundAction
|
||||
"""
|
||||
return self._client.retry_issuance(self)
|
||||
|
||||
|
||||
class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "certificates"
|
||||
class CertificatesPageResult(NamedTuple):
|
||||
certificates: list[BoundCertificate]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundCertificate
|
||||
|
||||
class CertificatesClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundCertificate:
|
||||
"""Get a specific certificate by its ID.
|
||||
|
||||
:param id: int
|
||||
|
@ -96,12 +117,11 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundCertificate], Meta]
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> CertificatesPageResult:
|
||||
"""Get a list of certificates
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -114,7 +134,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
|
||||
|
@ -136,10 +156,13 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for certificate_data in response["certificates"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(certificates, response)
|
||||
return CertificatesPageResult(certificates, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None, label_selector=None):
|
||||
# type: (Optional[str], Optional[str]) -> List[BoundCertificate]
|
||||
def get_all(
|
||||
self,
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
) -> list[BoundCertificate]:
|
||||
"""Get all certificates
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -148,20 +171,24 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter certificates by labels. The response will only contain certificates matching the label selector.
|
||||
:return: List[:class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`]
|
||||
"""
|
||||
return super().get_all(name=name, label_selector=label_selector)
|
||||
return self._iter_pages(self.get_list, name=name, label_selector=label_selector)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundCertificate
|
||||
def get_by_name(self, name: str) -> BoundCertificate | None:
|
||||
"""Get certificate by name
|
||||
|
||||
:param name: str
|
||||
Used to get certificate by name.
|
||||
:return: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(self, name, certificate, private_key, labels=None):
|
||||
# type: (str, str, str, Optional[Dict[str, str]]) -> BoundCertificate
|
||||
def create(
|
||||
self,
|
||||
name: str,
|
||||
certificate: str,
|
||||
private_key: str,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundCertificate:
|
||||
"""Creates a new Certificate with the given name, certificate and private_key. This methods allows only creating
|
||||
custom uploaded certificates. If you want to create a managed certificate use :func:`~hcloud.certificates.client.CertificatesClient.create_managed`
|
||||
|
||||
|
@ -174,7 +201,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`
|
||||
"""
|
||||
data = {
|
||||
data: dict[str, Any] = {
|
||||
"name": name,
|
||||
"certificate": certificate,
|
||||
"private_key": private_key,
|
||||
|
@ -185,8 +212,12 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
response = self._client.request(url="/certificates", method="POST", json=data)
|
||||
return BoundCertificate(self, response["certificate"])
|
||||
|
||||
def create_managed(self, name, domain_names, labels=None):
|
||||
# type: (str, List[str], Optional[Dict[str, str]]) -> CreateManagedCertificateResponse
|
||||
def create_managed(
|
||||
self,
|
||||
name: str,
|
||||
domain_names: list[str],
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> CreateManagedCertificateResponse:
|
||||
"""Creates a new managed Certificate with the given name and domain names. This methods allows only creating
|
||||
managed certificates for domains that are using the Hetzner DNS service. If you want to create a custom uploaded certificate use :func:`~hcloud.certificates.client.CertificatesClient.create`
|
||||
|
||||
|
@ -197,7 +228,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`
|
||||
"""
|
||||
data = {
|
||||
data: dict[str, Any] = {
|
||||
"name": name,
|
||||
"type": Certificate.TYPE_MANAGED,
|
||||
"domain_names": domain_names,
|
||||
|
@ -210,8 +241,12 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
action=BoundAction(self._client.actions, response["action"]),
|
||||
)
|
||||
|
||||
def update(self, certificate, name=None, labels=None):
|
||||
# type: (Certificate, Optional[str], Optional[Dict[str, str]]) -> BoundCertificate
|
||||
def update(
|
||||
self,
|
||||
certificate: Certificate | BoundCertificate,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundCertificate:
|
||||
"""Updates a Certificate. You can update a certificate name and labels.
|
||||
|
||||
:param certificate: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>` or :class:`Certificate <hcloud.certificates.domain.Certificate>`
|
||||
|
@ -221,7 +256,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
data["name"] = name
|
||||
if labels is not None:
|
||||
|
@ -233,24 +268,27 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundCertificate(self, response["certificate"])
|
||||
|
||||
def delete(self, certificate):
|
||||
# type: (Certificate) -> bool
|
||||
self._client.request(
|
||||
url=f"/certificates/{certificate.id}",
|
||||
method="DELETE",
|
||||
)
|
||||
def delete(self, certificate: Certificate | BoundCertificate) -> bool:
|
||||
"""Deletes a certificate.
|
||||
|
||||
:param certificate: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>` or :class:`Certificate <hcloud.certificates.domain.Certificate>`
|
||||
:return: True
|
||||
"""
|
||||
self._client.request(
|
||||
url=f"/certificates/{certificate.id}",
|
||||
method="DELETE",
|
||||
)
|
||||
# Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised
|
||||
return True
|
||||
|
||||
def get_actions_list(
|
||||
self, certificate, status=None, sort=None, page=None, per_page=None
|
||||
):
|
||||
# type: (Certificate, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta]
|
||||
self,
|
||||
certificate: Certificate | BoundCertificate,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a Certificate.
|
||||
|
||||
:param certificate: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>` or :class:`Certificate <hcloud.certificates.domain.Certificate>`
|
||||
|
@ -264,7 +302,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -275,9 +313,7 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
params["per_page"] = per_page
|
||||
|
||||
response = self._client.request(
|
||||
url="/certificates/{certificate_id}/actions".format(
|
||||
certificate_id=certificate.id
|
||||
),
|
||||
url=f"/certificates/{certificate.id}/actions",
|
||||
method="GET",
|
||||
params=params,
|
||||
)
|
||||
|
@ -285,10 +321,14 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(self, certificate, status=None, sort=None):
|
||||
# type: (Certificate, Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
certificate: Certificate | BoundCertificate,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Certificate.
|
||||
|
||||
:param certificate: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>` or :class:`Certificate <hcloud.certificates.domain.Certificate>`
|
||||
|
@ -298,19 +338,24 @@ class CertificatesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
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 <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(certificate, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
certificate,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def retry_issuance(self, certificate):
|
||||
# type: (Certificate) -> BoundAction
|
||||
def retry_issuance(
|
||||
self,
|
||||
certificate: Certificate | BoundCertificate,
|
||||
) -> BoundAction:
|
||||
"""Returns all action objects for a Certificate.
|
||||
|
||||
:param certificate: :class:`BoundCertificate <hcloud.certificates.client.BoundCertificate>` or :class:`Certificate <hcloud.certificates.domain.Certificate>`
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/certificates/{certificate_id}/actions/retry".format(
|
||||
certificate_id=certificate.id
|
||||
),
|
||||
url=f"/certificates/{certificate.id}/actions/retry",
|
||||
method="POST",
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from .client import BoundCertificate
|
||||
|
||||
|
||||
class Certificate(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -44,17 +52,17 @@ class Certificate(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
certificate=None,
|
||||
not_valid_before=None,
|
||||
not_valid_after=None,
|
||||
domain_names=None,
|
||||
fingerprint=None,
|
||||
created=None,
|
||||
labels=None,
|
||||
type=None,
|
||||
status=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
certificate: str | None = None,
|
||||
not_valid_before: str | None = None,
|
||||
not_valid_after: str | None = None,
|
||||
domain_names: list[str] | None = None,
|
||||
fingerprint: str | None = None,
|
||||
created: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
type: str | None = None,
|
||||
status: ManagedCertificateStatus | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -80,7 +88,12 @@ class ManagedCertificateStatus(BaseDomain):
|
|||
If issuance or renewal reports failure, this property contains information about what happened
|
||||
"""
|
||||
|
||||
def __init__(self, issuance=None, renewal=None, error=None):
|
||||
def __init__(
|
||||
self,
|
||||
issuance: str | None = None,
|
||||
renewal: str | None = None,
|
||||
error: ManagedCertificateError | None = None,
|
||||
):
|
||||
self.issuance = issuance
|
||||
self.renewal = renewal
|
||||
self.error = error
|
||||
|
@ -95,7 +108,7 @@ class ManagedCertificateError(BaseDomain):
|
|||
Message detailing the error
|
||||
"""
|
||||
|
||||
def __init__(self, code=None, message=None):
|
||||
def __init__(self, code: str | None = None, message: str | None = None):
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
||||
|
@ -113,8 +126,8 @@ class CreateManagedCertificateResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
certificate, # type: BoundCertificate
|
||||
action, # type: BoundAction
|
||||
certificate: BoundCertificate,
|
||||
action: BoundAction,
|
||||
):
|
||||
self.certificate = certificate
|
||||
self.action = action
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundModelBase, ClientEntityBase # noqa: F401
|
||||
from .domain import BaseDomain, DomainIdentityMixin, Meta, Pagination # noqa: F401
|
108
plugins/module_utils/vendor/hcloud/core/client.py
vendored
108
plugins/module_utils/vendor/hcloud/core/client.py
vendored
|
@ -1,102 +1,65 @@
|
|||
from .domain import add_meta_to_result
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class ClientEntityBase:
|
||||
max_per_page = 50
|
||||
results_list_attribute_name = None
|
||||
_client: Client
|
||||
|
||||
def __init__(self, client):
|
||||
max_per_page: int = 50
|
||||
|
||||
def __init__(self, client: Client):
|
||||
"""
|
||||
:param client: Client
|
||||
:return self
|
||||
"""
|
||||
self._client = client
|
||||
|
||||
def _is_list_attribute_implemented(self):
|
||||
if self.results_list_attribute_name is None:
|
||||
raise NotImplementedError(
|
||||
"in order to get results list, 'results_list_attribute_name' attribute of {} has to be specified".format(
|
||||
self.__class__.__name__
|
||||
)
|
||||
)
|
||||
|
||||
def _add_meta_to_result(
|
||||
def _iter_pages( # type: ignore[no-untyped-def]
|
||||
self,
|
||||
results, # type: List[BoundModelBase]
|
||||
response, # type: json
|
||||
):
|
||||
# type: (...) -> PageResult
|
||||
self._is_list_attribute_implemented()
|
||||
return add_meta_to_result(results, response, self.results_list_attribute_name)
|
||||
|
||||
def _get_all(
|
||||
self,
|
||||
list_function, # type: function
|
||||
results_list_attribute_name, # type: str
|
||||
list_function: Callable,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
# type (...) -> List[BoundModelBase]
|
||||
|
||||
page = 1
|
||||
|
||||
**kwargs,
|
||||
) -> list:
|
||||
results = []
|
||||
|
||||
page = 1
|
||||
while page:
|
||||
page_result = list_function(
|
||||
page=page, per_page=self.max_per_page, *args, **kwargs
|
||||
# The *PageResult tuples MUST have the following structure
|
||||
# `(result: List[Bound*], meta: Meta)`
|
||||
result, meta = list_function(
|
||||
*args, page=page, per_page=self.max_per_page, **kwargs
|
||||
)
|
||||
result = getattr(page_result, results_list_attribute_name)
|
||||
if result:
|
||||
results.extend(result)
|
||||
meta = page_result.meta
|
||||
if (
|
||||
meta
|
||||
and meta.pagination
|
||||
and meta.pagination.next_page
|
||||
and meta.pagination.next_page
|
||||
):
|
||||
|
||||
if meta and meta.pagination and meta.pagination.next_page:
|
||||
page = meta.pagination.next_page
|
||||
else:
|
||||
page = None
|
||||
page = 0
|
||||
|
||||
return results
|
||||
|
||||
def get_all(self, *args, **kwargs):
|
||||
# type: (...) -> List[BoundModelBase]
|
||||
self._is_list_attribute_implemented()
|
||||
return self._get_all(
|
||||
self.get_list, self.results_list_attribute_name, *args, **kwargs
|
||||
)
|
||||
|
||||
def get_actions(self, *args, **kwargs):
|
||||
# type: (...) -> List[BoundModelBase]
|
||||
if not hasattr(self, "get_actions_list"):
|
||||
raise ValueError("this endpoint does not support get_actions method")
|
||||
|
||||
return self._get_all(self.get_actions_list, "actions", *args, **kwargs)
|
||||
|
||||
|
||||
class GetEntityByNameMixin:
|
||||
"""
|
||||
Use as a mixin for ClientEntityBase classes
|
||||
"""
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundModelBase
|
||||
self._is_list_attribute_implemented()
|
||||
response = self.get_list(name=name)
|
||||
entities = getattr(response, self.results_list_attribute_name)
|
||||
entity = entities[0] if entities else None
|
||||
return entity
|
||||
def _get_first_by(self, **kwargs): # type: ignore[no-untyped-def]
|
||||
assert hasattr(self, "get_list")
|
||||
entities, _ = self.get_list(**kwargs)
|
||||
return entities[0] if entities else None
|
||||
|
||||
|
||||
class BoundModelBase:
|
||||
"""Bound Model Base"""
|
||||
|
||||
model = None
|
||||
model: Any
|
||||
|
||||
def __init__(self, client, data={}, complete=True):
|
||||
def __init__(
|
||||
self,
|
||||
client: ClientEntityBase,
|
||||
data: dict,
|
||||
complete: bool = True,
|
||||
):
|
||||
"""
|
||||
:param client:
|
||||
The client for the specific model to use
|
||||
|
@ -109,7 +72,7 @@ class BoundModelBase:
|
|||
self.complete = complete
|
||||
self.data_model = self.model.from_dict(data)
|
||||
|
||||
def __getattr__(self, name):
|
||||
def __getattr__(self, name: str): # type: ignore[no-untyped-def]
|
||||
"""Allow magical access to the properties of the model
|
||||
:param name: str
|
||||
:return:
|
||||
|
@ -120,8 +83,9 @@ class BoundModelBase:
|
|||
value = getattr(self.data_model, name)
|
||||
return value
|
||||
|
||||
def reload(self):
|
||||
def reload(self) -> None:
|
||||
"""Reloads the model and tries to get all data from the APIx"""
|
||||
assert hasattr(self._client, "get_by_id")
|
||||
bound_model = self._client.get_by_id(self.data_model.id)
|
||||
self.data_model = bound_model.data_model
|
||||
self.complete = True
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
from collections import namedtuple
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class BaseDomain:
|
||||
__slots__ = ()
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data):
|
||||
def from_dict(cls, data: dict): # type: ignore[no-untyped-def]
|
||||
supported_data = {k: v for k, v in data.items() if k in cls.__slots__}
|
||||
return cls(**supported_data)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
kwargs = [f"{key}={getattr(self, key)!r}" for key in self.__slots__]
|
||||
kwargs = [f"{key}={getattr(self, key)!r}" for key in self.__slots__] # type: ignore[var-annotated]
|
||||
return f"{self.__class__.__qualname__}({', '.join(kwargs)})"
|
||||
|
||||
|
||||
class DomainIdentityMixin:
|
||||
__slots__ = ()
|
||||
|
||||
id: int | None
|
||||
name: str | None
|
||||
|
||||
@property
|
||||
def id_or_name(self):
|
||||
def id_or_name(self) -> int | str:
|
||||
if self.id is not None:
|
||||
return self.id
|
||||
elif self.name is not None:
|
||||
|
@ -39,12 +42,12 @@ class Pagination(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
page,
|
||||
per_page,
|
||||
previous_page=None,
|
||||
next_page=None,
|
||||
last_page=None,
|
||||
total_entries=None,
|
||||
page: int,
|
||||
per_page: int,
|
||||
previous_page: int | None = None,
|
||||
next_page: int | None = None,
|
||||
last_page: int | None = None,
|
||||
total_entries: int | None = None,
|
||||
):
|
||||
self.page = page
|
||||
self.per_page = per_page
|
||||
|
@ -57,23 +60,17 @@ class Pagination(BaseDomain):
|
|||
class Meta(BaseDomain):
|
||||
__slots__ = ("pagination",)
|
||||
|
||||
def __init__(self, pagination=None):
|
||||
def __init__(self, pagination: Pagination | None = None):
|
||||
self.pagination = pagination
|
||||
|
||||
@classmethod
|
||||
def parse_meta(cls, json_content):
|
||||
def parse_meta(cls, response: dict) -> Meta | None:
|
||||
meta = None
|
||||
if json_content and "meta" in json_content:
|
||||
if response and "meta" in response:
|
||||
meta = cls()
|
||||
pagination_json = json_content["meta"].get("pagination")
|
||||
if pagination_json:
|
||||
pagination = Pagination(**pagination_json)
|
||||
meta.pagination = pagination
|
||||
try:
|
||||
meta.pagination = Pagination(**response["meta"]["pagination"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return meta
|
||||
|
||||
|
||||
def add_meta_to_result(result, json_content, attr_name):
|
||||
# type: (List[BoundModelBase], json, string) -> PageResult
|
||||
class_name = f"PageResults{attr_name.capitalize()}"
|
||||
PageResults = namedtuple(class_name, [attr_name, "meta"])
|
||||
return PageResults(**{attr_name: result, "meta": Meta.parse_meta(json_content)})
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundDatacenter,
|
||||
DatacentersClient,
|
||||
DatacentersPageResult,
|
||||
)
|
||||
from .domain import Datacenter, DatacenterServerTypes # noqa: F401
|
|
@ -1,13 +1,22 @@
|
|||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..locations.client import BoundLocation
|
||||
from ..server_types.client import BoundServerType
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from ..locations import BoundLocation
|
||||
from ..server_types import BoundServerType
|
||||
from .domain import Datacenter, DatacenterServerTypes
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundDatacenter(BoundModelBase):
|
||||
_client: DatacentersClient
|
||||
|
||||
model = Datacenter
|
||||
|
||||
def __init__(self, client, data):
|
||||
def __init__(self, client: DatacentersClient, data: dict):
|
||||
location = data.get("location")
|
||||
if location is not None:
|
||||
data["location"] = BoundLocation(client._client.locations, location)
|
||||
|
@ -41,11 +50,15 @@ class BoundDatacenter(BoundModelBase):
|
|||
super().__init__(client, data)
|
||||
|
||||
|
||||
class DatacentersClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "datacenters"
|
||||
class DatacentersPageResult(NamedTuple):
|
||||
datacenters: list[BoundDatacenter]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundDatacenter
|
||||
|
||||
class DatacentersClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundDatacenter:
|
||||
"""Get a specific datacenter by its ID.
|
||||
|
||||
:param id: int
|
||||
|
@ -56,11 +69,10 @@ class DatacentersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundDatacenter], Meta]
|
||||
name: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> DatacentersPageResult:
|
||||
"""Get a list of datacenters
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -71,7 +83,7 @@ class DatacentersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundDatacenter <hcloud.datacenters.client.BoundDatacenter>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
|
||||
|
@ -88,24 +100,22 @@ class DatacentersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for datacenter_data in response["datacenters"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(datacenters, response)
|
||||
return DatacentersPageResult(datacenters, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None):
|
||||
# type: (Optional[str]) -> List[BoundDatacenter]
|
||||
def get_all(self, name: str | None = None) -> list[BoundDatacenter]:
|
||||
"""Get all datacenters
|
||||
|
||||
:param name: str (optional)
|
||||
Can be used to filter datacenters by their name.
|
||||
:return: List[:class:`BoundDatacenter <hcloud.datacenters.client.BoundDatacenter>`]
|
||||
"""
|
||||
return super().get_all(name=name)
|
||||
return self._iter_pages(self.get_list, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundDatacenter
|
||||
def get_by_name(self, name: str) -> BoundDatacenter | None:
|
||||
"""Get datacenter by name
|
||||
|
||||
:param name: str
|
||||
Used to get datacenter by name.
|
||||
:return: :class:`BoundDatacenter <hcloud.datacenters.client.BoundDatacenter>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..locations import Location
|
||||
from ..server_types import BoundServerType
|
||||
|
||||
|
||||
class Datacenter(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -14,7 +22,12 @@ class Datacenter(BaseDomain, DomainIdentityMixin):
|
|||
__slots__ = ("id", "name", "description", "location", "server_types")
|
||||
|
||||
def __init__(
|
||||
self, id=None, name=None, description=None, location=None, server_types=None
|
||||
self,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
location: Location | None = None,
|
||||
server_types: DatacenterServerTypes | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -36,7 +49,12 @@ class DatacenterServerTypes:
|
|||
|
||||
__slots__ = ("available", "supported", "available_for_migration")
|
||||
|
||||
def __init__(self, available, supported, available_for_migration):
|
||||
def __init__(
|
||||
self,
|
||||
available: list[BoundServerType],
|
||||
supported: list[BoundServerType],
|
||||
available_for_migration: list[BoundServerType],
|
||||
):
|
||||
self.available = available
|
||||
self.supported = supported
|
||||
self.available_for_migration = available_for_migration
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .domain import DeprecationInfo # noqa: F401
|
|
@ -1,9 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
|
||||
class DeprecationInfo(BaseDomain):
|
||||
|
@ -25,8 +27,8 @@ class DeprecationInfo(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
announced=None,
|
||||
unavailable_after=None,
|
||||
announced: str | None = None,
|
||||
unavailable_after: str | None = None,
|
||||
):
|
||||
self.announced = isoparse(announced) if announced else None
|
||||
self.unavailable_after = (
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundFirewall, FirewallsClient, FirewallsPageResult # noqa: F401
|
||||
from .domain import ( # noqa: F401
|
||||
CreateFirewallResponse,
|
||||
Firewall,
|
||||
FirewallResource,
|
||||
FirewallResourceLabelSelector,
|
||||
FirewallRule,
|
||||
)
|
|
@ -1,6 +1,9 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import (
|
||||
CreateFirewallResponse,
|
||||
Firewall,
|
||||
|
@ -9,11 +12,16 @@ from .domain import (
|
|||
FirewallRule,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundFirewall(BoundModelBase):
|
||||
_client: FirewallsClient
|
||||
|
||||
model = Firewall
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
def __init__(self, client: FirewallsClient, data: dict, complete: bool = True):
|
||||
rules = data.get("rules", [])
|
||||
if rules:
|
||||
rules = [
|
||||
|
@ -31,7 +39,7 @@ class BoundFirewall(BoundModelBase):
|
|||
|
||||
applied_to = data.get("applied_to", [])
|
||||
if applied_to:
|
||||
from ..servers.client import BoundServer
|
||||
from ..servers import BoundServer
|
||||
|
||||
ats = []
|
||||
for a in applied_to:
|
||||
|
@ -57,8 +65,13 @@ class BoundFirewall(BoundModelBase):
|
|||
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResult[BoundAction, Meta]
|
||||
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 action objects for a Firewall.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -73,8 +86,11 @@ class BoundFirewall(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Firewall.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -86,8 +102,11 @@ class BoundFirewall(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def update(self, name=None, labels=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]], Optional[str]) -> BoundFirewall
|
||||
def update(
|
||||
self,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundFirewall:
|
||||
"""Updates the name or labels of a Firewall.
|
||||
|
||||
:param labels: Dict[str, str] (optional)
|
||||
|
@ -98,16 +117,14 @@ class BoundFirewall(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, labels, name)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a Firewall.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def set_rules(self, rules):
|
||||
# type: (List[FirewallRule]) -> List[BoundAction]
|
||||
def set_rules(self, rules: list[FirewallRule]) -> list[BoundAction]:
|
||||
"""Sets the rules of a Firewall. All existing rules will be overwritten. Pass an empty rules array to remove all rules.
|
||||
:param rules: List[:class:`FirewallRule <hcloud.firewalls.domain.FirewallRule>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
|
@ -115,16 +132,20 @@ class BoundFirewall(BoundModelBase):
|
|||
|
||||
return self._client.set_rules(self, rules)
|
||||
|
||||
def apply_to_resources(self, resources):
|
||||
# type: (List[FirewallResource]) -> List[BoundAction]
|
||||
def apply_to_resources(
|
||||
self,
|
||||
resources: list[FirewallResource],
|
||||
) -> list[BoundAction]:
|
||||
"""Applies one Firewall to multiple resources.
|
||||
:param resources: List[:class:`FirewallResource <hcloud.firewalls.domain.FirewallResource>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return self._client.apply_to_resources(self, resources)
|
||||
|
||||
def remove_from_resources(self, resources):
|
||||
# type: (List[FirewallResource]) -> List[BoundAction]
|
||||
def remove_from_resources(
|
||||
self,
|
||||
resources: list[FirewallResource],
|
||||
) -> list[BoundAction]:
|
||||
"""Removes one Firewall from multiple resources.
|
||||
:param resources: List[:class:`FirewallResource <hcloud.firewalls.domain.FirewallResource>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
|
@ -132,18 +153,22 @@ class BoundFirewall(BoundModelBase):
|
|||
return self._client.remove_from_resources(self, resources)
|
||||
|
||||
|
||||
class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "firewalls"
|
||||
class FirewallsPageResult(NamedTuple):
|
||||
firewalls: list[BoundFirewall]
|
||||
meta: Meta | None
|
||||
|
||||
|
||||
class FirewallsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_actions_list(
|
||||
self,
|
||||
firewall, # type: Firewall
|
||||
status=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundAction], Meta]
|
||||
firewall: Firewall | BoundFirewall,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a Firewall.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
|
@ -157,7 +182,7 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -175,15 +200,14 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(
|
||||
self,
|
||||
firewall, # type: Firewall
|
||||
status=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
):
|
||||
# type: (...) -> List[BoundAction]
|
||||
firewall: Firewall | BoundFirewall,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Firewall.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
|
@ -194,10 +218,14 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(firewall, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
firewall,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundFirewall
|
||||
def get_by_id(self, id: int) -> BoundFirewall:
|
||||
"""Returns a specific Firewall object.
|
||||
|
||||
:param id: int
|
||||
|
@ -208,13 +236,12 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
name=None, # type: Optional[str]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundFirewall]]
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
name: str | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> FirewallsPageResult:
|
||||
"""Get a list of floating ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -229,7 +256,7 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default))
|
||||
:return: (List[:class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
|
||||
if label_selector is not None:
|
||||
params["label_selector"] = label_selector
|
||||
|
@ -247,10 +274,14 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for firewall_data in response["firewalls"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(firewalls, response)
|
||||
return FirewallsPageResult(firewalls, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, label_selector=None, name=None, sort=None):
|
||||
# type: (Optional[str], Optional[str], Optional[List[str]]) -> List[BoundFirewall]
|
||||
def get_all(
|
||||
self,
|
||||
label_selector: str | None = None,
|
||||
name: str | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundFirewall]:
|
||||
"""Get all floating ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -261,26 +292,29 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default))
|
||||
:return: List[:class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>`]
|
||||
"""
|
||||
return super().get_all(label_selector=label_selector, name=name, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
label_selector=label_selector,
|
||||
name=name,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundFirewall
|
||||
def get_by_name(self, name: str) -> BoundFirewall | None:
|
||||
"""Get Firewall by name
|
||||
|
||||
:param name: str
|
||||
Used to get Firewall by name.
|
||||
:return: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
name, # type: str
|
||||
rules=None, # type: Optional[List[FirewallRule]]
|
||||
labels=None, # type: Optional[str]
|
||||
resources=None, # type: Optional[List[FirewallResource]]
|
||||
):
|
||||
# type: (...) -> CreateFirewallResponse
|
||||
name: str,
|
||||
rules: list[FirewallRule] | None = None,
|
||||
labels: str | None = None,
|
||||
resources: list[FirewallResource] | None = None,
|
||||
) -> CreateFirewallResponse:
|
||||
"""Creates a new Firewall.
|
||||
|
||||
:param name: str
|
||||
|
@ -292,7 +326,7 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`CreateFirewallResponse <hcloud.firewalls.domain.CreateFirewallResponse>`
|
||||
"""
|
||||
|
||||
data = {"name": name}
|
||||
data: dict[str, Any] = {"name": name}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
|
||||
|
@ -309,7 +343,8 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
actions = []
|
||||
if response.get("actions") is not None:
|
||||
actions = [
|
||||
BoundAction(self._client.actions, _) for _ in response["actions"]
|
||||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
|
||||
result = CreateFirewallResponse(
|
||||
|
@ -317,8 +352,12 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return result
|
||||
|
||||
def update(self, firewall, labels=None, name=None):
|
||||
# type: (Firewall, Optional[Dict[str, str]], Optional[str]) -> BoundFirewall
|
||||
def update(
|
||||
self,
|
||||
firewall: Firewall | BoundFirewall,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundFirewall:
|
||||
"""Updates the description or labels of a Firewall.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
|
@ -328,7 +367,7 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
New name to set
|
||||
:return: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
if name is not None:
|
||||
|
@ -341,8 +380,7 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundFirewall(self, response["firewall"])
|
||||
|
||||
def delete(self, firewall):
|
||||
# type: (Firewall) -> bool
|
||||
def delete(self, firewall: Firewall | BoundFirewall) -> bool:
|
||||
"""Deletes a Firewall.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
|
@ -355,62 +393,74 @@ class FirewallsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
# Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised
|
||||
return True
|
||||
|
||||
def set_rules(self, firewall, rules):
|
||||
# type: (Firewall, List[FirewallRule]) -> List[BoundAction]
|
||||
def set_rules(
|
||||
self,
|
||||
firewall: Firewall | BoundFirewall,
|
||||
rules: list[FirewallRule],
|
||||
) -> list[BoundAction]:
|
||||
"""Sets the rules of a Firewall. All existing rules will be overwritten. Pass an empty rules array to remove all rules.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
:param rules: List[:class:`FirewallRule <hcloud.firewalls.domain.FirewallRule>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
data = {"rules": []}
|
||||
data: dict[str, Any] = {"rules": []}
|
||||
for rule in rules:
|
||||
data["rules"].append(rule.to_payload())
|
||||
response = self._client.request(
|
||||
url="/firewalls/{firewall_id}/actions/set_rules".format(
|
||||
firewall_id=firewall.id
|
||||
),
|
||||
url=f"/firewalls/{firewall.id}/actions/set_rules",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return [BoundAction(self._client.actions, _) for _ in response["actions"]]
|
||||
return [
|
||||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
|
||||
def apply_to_resources(self, firewall, resources):
|
||||
# type: (Firewall, List[FirewallResource]) -> List[BoundAction]
|
||||
def apply_to_resources(
|
||||
self,
|
||||
firewall: Firewall | BoundFirewall,
|
||||
resources: list[FirewallResource],
|
||||
) -> list[BoundAction]:
|
||||
"""Applies one Firewall to multiple resources.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
:param resources: List[:class:`FirewallResource <hcloud.firewalls.domain.FirewallResource>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
data = {"apply_to": []}
|
||||
data: dict[str, Any] = {"apply_to": []}
|
||||
for resource in resources:
|
||||
data["apply_to"].append(resource.to_payload())
|
||||
response = self._client.request(
|
||||
url="/firewalls/{firewall_id}/actions/apply_to_resources".format(
|
||||
firewall_id=firewall.id
|
||||
),
|
||||
url=f"/firewalls/{firewall.id}/actions/apply_to_resources",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return [BoundAction(self._client.actions, _) for _ in response["actions"]]
|
||||
return [
|
||||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
|
||||
def remove_from_resources(self, firewall, resources):
|
||||
# type: (Firewall, List[FirewallResource]) -> List[BoundAction]
|
||||
def remove_from_resources(
|
||||
self,
|
||||
firewall: Firewall | BoundFirewall,
|
||||
resources: list[FirewallResource],
|
||||
) -> list[BoundAction]:
|
||||
"""Removes one Firewall from multiple resources.
|
||||
|
||||
:param firewall: :class:`BoundFirewall <hcloud.firewalls.client.BoundFirewall>` or :class:`Firewall <hcloud.firewalls.domain.Firewall>`
|
||||
:param resources: List[:class:`FirewallResource <hcloud.firewalls.domain.FirewallResource>`]
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
data = {"remove_from": []}
|
||||
data: dict[str, Any] = {"remove_from": []}
|
||||
for resource in resources:
|
||||
data["remove_from"].append(resource.to_payload())
|
||||
response = self._client.request(
|
||||
url="/firewalls/{firewall_id}/actions/remove_from_resources".format(
|
||||
firewall_id=firewall.id
|
||||
),
|
||||
url=f"/firewalls/{firewall.id}/actions/remove_from_resources",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return [BoundAction(self._client.actions, _) for _ in response["actions"]]
|
||||
return [
|
||||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..servers import BoundServer, Server
|
||||
from .client import BoundFirewall
|
||||
|
||||
|
||||
class Firewall(BaseDomain):
|
||||
|
@ -26,7 +35,13 @@ class Firewall(BaseDomain):
|
|||
__slots__ = ("id", "name", "labels", "rules", "applied_to", "created")
|
||||
|
||||
def __init__(
|
||||
self, id=None, name=None, labels=None, rules=None, applied_to=None, created=None
|
||||
self,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
rules: list[FirewallRule] | None = None,
|
||||
applied_to: list[FirewallResource] | None = None,
|
||||
created: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -81,12 +96,12 @@ class FirewallRule:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
direction, # type: str
|
||||
protocol, # type: str
|
||||
source_ips, # type: List[str]
|
||||
port=None, # type: Optional[str]
|
||||
destination_ips=None, # type: Optional[List[str]]
|
||||
description=None, # type: Optional[str]
|
||||
direction: str,
|
||||
protocol: str,
|
||||
source_ips: list[str],
|
||||
port: str | None = None,
|
||||
destination_ips: list[str] | None = None,
|
||||
description: str | None = None,
|
||||
):
|
||||
self.direction = direction
|
||||
self.port = port
|
||||
|
@ -95,18 +110,18 @@ class FirewallRule:
|
|||
self.destination_ips = destination_ips or []
|
||||
self.description = description
|
||||
|
||||
def to_payload(self):
|
||||
payload = {
|
||||
def to_payload(self) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {
|
||||
"direction": self.direction,
|
||||
"protocol": self.protocol,
|
||||
"source_ips": self.source_ips,
|
||||
}
|
||||
if len(self.destination_ips) > 0:
|
||||
payload.update({"destination_ips": self.destination_ips})
|
||||
payload["destination_ips"] = self.destination_ips
|
||||
if self.port is not None:
|
||||
payload.update({"port": self.port})
|
||||
payload["port"] = self.port
|
||||
if self.description is not None:
|
||||
payload.update({"description": self.description})
|
||||
payload["description"] = self.description
|
||||
return payload
|
||||
|
||||
|
||||
|
@ -130,23 +145,21 @@ class FirewallResource:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
type, # type: str
|
||||
server=None, # type: Optional[Server]
|
||||
label_selector=None, # type: Optional[FirewallResourceLabelSelector]
|
||||
type: str,
|
||||
server: Server | BoundServer | None = None,
|
||||
label_selector: FirewallResourceLabelSelector | None = None,
|
||||
):
|
||||
self.type = type
|
||||
self.server = server
|
||||
self.label_selector = label_selector
|
||||
|
||||
def to_payload(self):
|
||||
payload = {"type": self.type}
|
||||
def to_payload(self) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {"type": self.type}
|
||||
if self.server is not None:
|
||||
payload.update({"server": {"id": self.server.id}})
|
||||
payload["server"] = {"id": self.server.id}
|
||||
|
||||
if self.label_selector is not None:
|
||||
payload.update(
|
||||
{"label_selector": {"selector": self.label_selector.selector}}
|
||||
)
|
||||
payload["label_selector"] = {"selector": self.label_selector.selector}
|
||||
return payload
|
||||
|
||||
|
||||
|
@ -156,7 +169,7 @@ class FirewallResourceLabelSelector(BaseDomain):
|
|||
:param selector: str Target label selector
|
||||
"""
|
||||
|
||||
def __init__(self, selector=None):
|
||||
def __init__(self, selector: str | None = None):
|
||||
self.selector = selector
|
||||
|
||||
|
||||
|
@ -173,8 +186,8 @@ class CreateFirewallResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
firewall, # type: BoundFirewall
|
||||
actions, # type: BoundAction
|
||||
firewall: BoundFirewall,
|
||||
actions: list[BoundAction] | None,
|
||||
):
|
||||
self.firewall = firewall
|
||||
self.actions = actions
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundFloatingIP,
|
||||
FloatingIPsClient,
|
||||
FloatingIPsPageResult,
|
||||
)
|
||||
from .domain import CreateFloatingIPResponse, FloatingIP # noqa: F401
|
|
@ -1,15 +1,25 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from ..locations.client import BoundLocation
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from ..locations import BoundLocation
|
||||
from .domain import CreateFloatingIPResponse, FloatingIP
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
from ..locations import Location
|
||||
from ..servers import BoundServer, Server
|
||||
|
||||
|
||||
class BoundFloatingIP(BoundModelBase):
|
||||
_client: FloatingIPsClient
|
||||
|
||||
model = FloatingIP
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
from ..servers.client import BoundServer
|
||||
def __init__(self, client: FloatingIPsClient, data: dict, complete: bool = True):
|
||||
from ..servers import BoundServer
|
||||
|
||||
server = data.get("server")
|
||||
if server is not None:
|
||||
|
@ -25,8 +35,13 @@ class BoundFloatingIP(BoundModelBase):
|
|||
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResult[BoundAction, Meta]
|
||||
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 action objects for a Floating IP.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -41,8 +56,11 @@ class BoundFloatingIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Floating IP.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -54,8 +72,12 @@ class BoundFloatingIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def update(self, description=None, labels=None, name=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]], Optional[str]) -> BoundFloatingIP
|
||||
def update(
|
||||
self,
|
||||
description: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundFloatingIP:
|
||||
"""Updates the description or labels of a Floating IP.
|
||||
|
||||
:param description: str (optional)
|
||||
|
@ -68,16 +90,14 @@ class BoundFloatingIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, description, labels, name)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a Floating IP. If it is currently assigned to a server it will automatically get unassigned.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def change_protection(self, delete=None):
|
||||
# type: (Optional[bool]) -> BoundAction
|
||||
def change_protection(self, delete: bool | None = None) -> BoundAction:
|
||||
"""Changes the protection configuration of the Floating IP.
|
||||
|
||||
:param delete: boolean
|
||||
|
@ -86,8 +106,7 @@ class BoundFloatingIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_protection(self, delete)
|
||||
|
||||
def assign(self, server):
|
||||
# type: (Server) -> BoundAction
|
||||
def assign(self, server: Server | BoundServer) -> BoundAction:
|
||||
"""Assigns a Floating IP to a server.
|
||||
|
||||
:param server: :class:`BoundServer <hcloud.servers.client.BoundServer>` or :class:`Server <hcloud.servers.domain.Server>`
|
||||
|
@ -96,16 +115,14 @@ class BoundFloatingIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.assign(self, server)
|
||||
|
||||
def unassign(self):
|
||||
# type: () -> BoundAction
|
||||
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.
|
||||
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
return self._client.unassign(self)
|
||||
|
||||
def change_dns_ptr(self, ip, dns_ptr):
|
||||
# type: (str, str) -> BoundAction
|
||||
def change_dns_ptr(self, ip: str, dns_ptr: str) -> BoundAction:
|
||||
"""Changes the hostname that will appear when getting the hostname belonging to this Floating IP.
|
||||
|
||||
:param ip: str
|
||||
|
@ -117,18 +134,22 @@ class BoundFloatingIP(BoundModelBase):
|
|||
return self._client.change_dns_ptr(self, ip, dns_ptr)
|
||||
|
||||
|
||||
class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "floating_ips"
|
||||
class FloatingIPsPageResult(NamedTuple):
|
||||
floating_ips: list[BoundFloatingIP]
|
||||
meta: Meta | None
|
||||
|
||||
|
||||
class FloatingIPsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_actions_list(
|
||||
self,
|
||||
floating_ip, # type: FloatingIP
|
||||
status=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundAction], Meta]
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a Floating IP.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -142,7 +163,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -152,9 +173,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
if per_page is not None:
|
||||
params["per_page"] = per_page
|
||||
response = self._client.request(
|
||||
url="/floating_ips/{floating_ip_id}/actions".format(
|
||||
floating_ip_id=floating_ip.id
|
||||
),
|
||||
url=f"/floating_ips/{floating_ip.id}/actions",
|
||||
method="GET",
|
||||
params=params,
|
||||
)
|
||||
|
@ -162,15 +181,14 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(
|
||||
self,
|
||||
floating_ip, # type: FloatingIP
|
||||
status=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
):
|
||||
# type: (...) -> List[BoundAction]
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Floating IP.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -181,10 +199,14 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(floating_ip, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
floating_ip,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundFloatingIP
|
||||
def get_by_id(self, id: int) -> BoundFloatingIP:
|
||||
"""Returns a specific Floating IP object.
|
||||
|
||||
:param id: int
|
||||
|
@ -195,12 +217,11 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
name=None, # type: Optional[str]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundFloatingIP]]
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
name: str | None = None,
|
||||
) -> FloatingIPsPageResult:
|
||||
"""Get a list of floating ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -213,7 +234,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter networks by their name.
|
||||
:return: (List[:class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
|
||||
if label_selector is not None:
|
||||
params["label_selector"] = label_selector
|
||||
|
@ -232,10 +253,13 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for floating_ip_data in response["floating_ips"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(floating_ips, response)
|
||||
return FloatingIPsPageResult(floating_ips, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, label_selector=None, name=None):
|
||||
# type: (Optional[str], Optional[str]) -> List[BoundFloatingIP]
|
||||
def get_all(
|
||||
self,
|
||||
label_selector: str | None = None,
|
||||
name: str | None = None,
|
||||
) -> list[BoundFloatingIP]:
|
||||
"""Get all floating ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -244,28 +268,26 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter networks by their name.
|
||||
:return: List[:class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>`]
|
||||
"""
|
||||
return super().get_all(label_selector=label_selector, name=name)
|
||||
return self._iter_pages(self.get_list, label_selector=label_selector, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundFloatingIP
|
||||
def get_by_name(self, name: str) -> BoundFloatingIP | None:
|
||||
"""Get Floating IP by name
|
||||
|
||||
:param name: str
|
||||
Used to get Floating IP by name.
|
||||
:return: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
type, # type: str
|
||||
description=None, # type: Optional[str]
|
||||
labels=None, # type: Optional[str]
|
||||
home_location=None, # type: Optional[Location]
|
||||
server=None, # type: Optional[Server]
|
||||
name=None, # type: Optional[str]
|
||||
):
|
||||
# type: (...) -> CreateFloatingIPResponse
|
||||
type: str,
|
||||
description: str | None = None,
|
||||
labels: str | None = None,
|
||||
home_location: Location | BoundLocation | None = None,
|
||||
server: Server | BoundServer | None = None,
|
||||
name: str | None = None,
|
||||
) -> CreateFloatingIPResponse:
|
||||
"""Creates a new Floating IP assigned to a server.
|
||||
|
||||
:param type: str
|
||||
|
@ -281,7 +303,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`CreateFloatingIPResponse <hcloud.floating_ips.domain.CreateFloatingIPResponse>`
|
||||
"""
|
||||
|
||||
data = {"type": type}
|
||||
data: dict[str, Any] = {"type": type}
|
||||
if description is not None:
|
||||
data["description"] = description
|
||||
if labels is not None:
|
||||
|
@ -304,8 +326,13 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return result
|
||||
|
||||
def update(self, floating_ip, description=None, labels=None, name=None):
|
||||
# type: (FloatingIP, Optional[str], Optional[Dict[str, str]], Optional[str]) -> BoundFloatingIP
|
||||
def update(
|
||||
self,
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
description: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundFloatingIP:
|
||||
"""Updates the description or labels of a Floating IP.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -317,7 +344,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
New name to set
|
||||
:return: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if description is not None:
|
||||
data["description"] = description
|
||||
if labels is not None:
|
||||
|
@ -332,8 +359,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundFloatingIP(self, response["floating_ip"])
|
||||
|
||||
def delete(self, floating_ip):
|
||||
# type: (FloatingIP) -> bool
|
||||
def delete(self, floating_ip: FloatingIP | BoundFloatingIP) -> bool:
|
||||
"""Deletes a Floating IP. If it is currently assigned to a server it will automatically get unassigned.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -346,8 +372,11 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
# Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised
|
||||
return True
|
||||
|
||||
def change_protection(self, floating_ip, delete=None):
|
||||
# type: (FloatingIP, Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of the Floating IP.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -355,21 +384,22 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If true, prevents the Floating IP from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/floating_ips/{floating_ip_id}/actions/change_protection".format(
|
||||
floating_ip_id=floating_ip.id
|
||||
),
|
||||
url=f"/floating_ips/{floating_ip.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def assign(self, floating_ip, server):
|
||||
# type: (FloatingIP, Server) -> BoundAction
|
||||
def assign(
|
||||
self,
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
server: Server | BoundServer,
|
||||
) -> BoundAction:
|
||||
"""Assigns a Floating IP to a server.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -378,31 +408,30 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/floating_ips/{floating_ip_id}/actions/assign".format(
|
||||
floating_ip_id=floating_ip.id
|
||||
),
|
||||
url=f"/floating_ips/{floating_ip.id}/actions/assign",
|
||||
method="POST",
|
||||
json={"server": server.id},
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def unassign(self, floating_ip):
|
||||
# type: (FloatingIP) -> BoundAction
|
||||
def unassign(self, floating_ip: FloatingIP | BoundFloatingIP) -> BoundAction:
|
||||
"""Unassigns a Floating IP, resulting in it being unreachable. You may assign it to a server again at a later time.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/floating_ips/{floating_ip_id}/actions/unassign".format(
|
||||
floating_ip_id=floating_ip.id
|
||||
),
|
||||
url=f"/floating_ips/{floating_ip.id}/actions/unassign",
|
||||
method="POST",
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_dns_ptr(self, floating_ip, ip, dns_ptr):
|
||||
# type: (FloatingIP, str, str) -> BoundAction
|
||||
def change_dns_ptr(
|
||||
self,
|
||||
floating_ip: FloatingIP | BoundFloatingIP,
|
||||
ip: str,
|
||||
dns_ptr: str,
|
||||
) -> BoundAction:
|
||||
"""Changes the hostname that will appear when getting the hostname belonging to this Floating IP.
|
||||
|
||||
:param floating_ip: :class:`BoundFloatingIP <hcloud.floating_ips.client.BoundFloatingIP>` or :class:`FloatingIP <hcloud.floating_ips.domain.FloatingIP>`
|
||||
|
@ -413,9 +442,7 @@ class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/floating_ips/{floating_ip_id}/actions/change_dns_ptr".format(
|
||||
floating_ip_id=floating_ip.id
|
||||
),
|
||||
url=f"/floating_ips/{floating_ip.id}/actions/change_dns_ptr",
|
||||
method="POST",
|
||||
json={"ip": ip, "dns_ptr": dns_ptr},
|
||||
)
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..locations import BoundLocation
|
||||
from ..servers import BoundServer
|
||||
from .client import BoundFloatingIP
|
||||
|
||||
|
||||
class FloatingIP(BaseDomain):
|
||||
|
@ -52,18 +62,18 @@ class FloatingIP(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
type=None,
|
||||
description=None,
|
||||
ip=None,
|
||||
server=None,
|
||||
dns_ptr=None,
|
||||
home_location=None,
|
||||
blocked=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
created=None,
|
||||
name=None,
|
||||
id: int | None = None,
|
||||
type: str | None = None,
|
||||
description: str | None = None,
|
||||
ip: str | None = None,
|
||||
server: BoundServer | None = None,
|
||||
dns_ptr: list[dict] | None = None,
|
||||
home_location: BoundLocation | None = None,
|
||||
blocked: bool | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
created: str | None = None,
|
||||
name: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.type = type
|
||||
|
@ -92,8 +102,8 @@ class CreateFloatingIPResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
floating_ip, # type: BoundFloatingIP
|
||||
action, # type: BoundAction
|
||||
floating_ip: BoundFloatingIP,
|
||||
action: BoundAction | None,
|
||||
):
|
||||
self.floating_ip = floating_ip
|
||||
self.action = action
|
||||
|
|
2
plugins/module_utils/vendor/hcloud/hcloud.py
vendored
2
plugins/module_utils/vendor/hcloud/hcloud.py
vendored
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
|
||||
warnings.warn(
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .labels import LabelValidator # noqa: F401
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Dict
|
||||
|
||||
|
||||
class LabelValidator:
|
||||
|
@ -11,7 +12,7 @@ class LabelValidator:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def validate(labels: Dict[str, str]) -> bool:
|
||||
def validate(labels: dict[str, str]) -> bool:
|
||||
"""Validates Labels. If you want to know which key/value pair of the dict is not correctly formatted
|
||||
use :func:`~hcloud.helpers.labels.validate_verbose`.
|
||||
|
||||
|
@ -25,7 +26,7 @@ class LabelValidator:
|
|||
return True
|
||||
|
||||
@staticmethod
|
||||
def validate_verbose(labels: Dict[str, str]) -> (bool, str):
|
||||
def validate_verbose(labels: dict[str, str]) -> tuple[bool, str]:
|
||||
"""Validates Labels and returns the corresponding error message if something is wrong. Returns True, <empty string>
|
||||
if everything is fine.
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundImage, ImagesClient, ImagesPageResult # noqa: F401
|
||||
from .domain import CreateImageResponse, Image # noqa: F401
|
186
plugins/module_utils/vendor/hcloud/images/client.py
vendored
186
plugins/module_utils/vendor/hcloud/images/client.py
vendored
|
@ -1,14 +1,22 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import Image
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundImage(BoundModelBase):
|
||||
_client: ImagesClient
|
||||
|
||||
model = Image
|
||||
|
||||
def __init__(self, client, data):
|
||||
from ..servers.client import BoundServer
|
||||
def __init__(self, client: ImagesClient, data: dict):
|
||||
from ..servers import BoundServer
|
||||
|
||||
created_from = data.get("created_from")
|
||||
if created_from is not None:
|
||||
|
@ -23,8 +31,13 @@ class BoundImage(BoundModelBase):
|
|||
|
||||
super().__init__(client, data)
|
||||
|
||||
def get_actions_list(self, sort=None, page=None, per_page=None, status=None):
|
||||
# type: (Optional[List[str]], Optional[int], Optional[int], Optional[List[str]]) -> PageResult[BoundAction, Meta]
|
||||
def get_actions_list(
|
||||
self,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns a list of action objects for the image.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -41,8 +54,11 @@ class BoundImage(BoundModelBase):
|
|||
self, sort=sort, page=page, per_page=per_page, status=status
|
||||
)
|
||||
|
||||
def get_actions(self, sort=None, status=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
sort: list[str] | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for the image.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -53,8 +69,12 @@ class BoundImage(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status=status, sort=sort)
|
||||
|
||||
def update(self, description=None, type=None, labels=None):
|
||||
# type: (Optional[str], Optional[str], Optional[Dict[str, str]]) -> BoundImage
|
||||
def update(
|
||||
self,
|
||||
description: str | None = None,
|
||||
type: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundImage:
|
||||
"""Updates the Image. You may change the description, convert a Backup image to a Snapshot Image or change the image labels.
|
||||
|
||||
:param description: str (optional)
|
||||
|
@ -68,16 +88,14 @@ class BoundImage(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, description, type, labels)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes an Image. Only images of type snapshot and backup can be deleted.
|
||||
|
||||
:return: bool
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def change_protection(self, delete=None):
|
||||
# type: (Optional[bool]) -> BoundAction
|
||||
def change_protection(self, delete: bool | None = None) -> BoundAction:
|
||||
"""Changes the protection configuration of the image. Can only be used on snapshots.
|
||||
|
||||
:param delete: bool
|
||||
|
@ -87,18 +105,22 @@ class BoundImage(BoundModelBase):
|
|||
return self._client.change_protection(self, delete)
|
||||
|
||||
|
||||
class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "images"
|
||||
class ImagesPageResult(NamedTuple):
|
||||
images: list[BoundImage]
|
||||
meta: Meta | None
|
||||
|
||||
|
||||
class ImagesClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_actions_list(
|
||||
self,
|
||||
image, # type: Image
|
||||
sort=None, # type: Optional[List[str]]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
status=None, # type: Optional[List[str]]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundAction], Meta]
|
||||
image: Image | BoundImage,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns a list of action objects for an image.
|
||||
|
||||
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.images.domain.Image>`
|
||||
|
@ -112,7 +134,7 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if sort is not None:
|
||||
params["sort"] = sort
|
||||
if status is not None:
|
||||
|
@ -130,15 +152,14 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(
|
||||
self,
|
||||
image, # type: Image
|
||||
sort=None, # type: Optional[List[str]]
|
||||
status=None, # type: Optional[List[str]]
|
||||
):
|
||||
# type: (...) -> List[BoundAction]
|
||||
image: Image | BoundImage,
|
||||
sort: list[str] | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for an image.
|
||||
|
||||
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.images.domain.Image>`
|
||||
|
@ -148,10 +169,14 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specify how the results are sorted. Choices: `id` `command` `status` `progress` `started` `finished` . You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default)
|
||||
:return: List[:class:`BoundAction <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(image, sort=sort, status=status)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
image,
|
||||
sort=sort,
|
||||
status=status,
|
||||
)
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundImage
|
||||
def get_by_id(self, id: int) -> BoundImage:
|
||||
"""Get a specific Image
|
||||
|
||||
:param id: int
|
||||
|
@ -162,18 +187,17 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
bound_to=None, # type: Optional[List[str]]
|
||||
type=None, # type: Optional[List[str]]
|
||||
architecture=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
status=None, # type: Optional[List[str]]
|
||||
include_deprecated=None, # type: Optional[bool]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundImage]]
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
bound_to: list[str] | None = None,
|
||||
type: list[str] | None = None,
|
||||
architecture: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
status: list[str] | None = None,
|
||||
include_deprecated: bool | None = None,
|
||||
) -> ImagesPageResult:
|
||||
"""Get all images
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -198,7 +222,7 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundImage <hcloud.images.client.BoundImage>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if label_selector is not None:
|
||||
|
@ -222,20 +246,19 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
response = self._client.request(url="/images", method="GET", params=params)
|
||||
images = [BoundImage(self, image_data) for image_data in response["images"]]
|
||||
|
||||
return self._add_meta_to_result(images, response)
|
||||
return ImagesPageResult(images, Meta.parse_meta(response))
|
||||
|
||||
def get_all(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
bound_to=None, # type: Optional[List[str]]
|
||||
type=None, # type: Optional[List[str]]
|
||||
architecture=None, # type: Optional[List[str]]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
status=None, # type: Optional[List[str]]
|
||||
include_deprecated=None, # type: Optional[bool]
|
||||
):
|
||||
# type: (...) -> List[BoundImage]
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
bound_to: list[str] | None = None,
|
||||
type: list[str] | None = None,
|
||||
architecture: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
status: list[str] | None = None,
|
||||
include_deprecated: bool | None = None,
|
||||
) -> list[BoundImage]:
|
||||
"""Get all images
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -256,7 +279,8 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Include deprecated images in the response. Default: False
|
||||
:return: List[:class:`BoundImage <hcloud.images.client.BoundImage>`]
|
||||
"""
|
||||
return super().get_all(
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
name=name,
|
||||
label_selector=label_selector,
|
||||
bound_to=bound_to,
|
||||
|
@ -267,8 +291,7 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
include_deprecated=include_deprecated,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundImage
|
||||
def get_by_name(self, name: str) -> BoundImage | None:
|
||||
"""Get image by name
|
||||
|
||||
Deprecated: Use get_by_name_and_architecture instead.
|
||||
|
@ -277,10 +300,13 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Used to get image by name.
|
||||
:return: :class:`BoundImage <hcloud.images.client.BoundImage>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def get_by_name_and_architecture(self, name, architecture):
|
||||
# type: (str, str) -> BoundImage
|
||||
def get_by_name_and_architecture(
|
||||
self,
|
||||
name: str,
|
||||
architecture: str,
|
||||
) -> BoundImage | None:
|
||||
"""Get image by name
|
||||
|
||||
:param name: str
|
||||
|
@ -289,13 +315,15 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Used to identify the image.
|
||||
:return: :class:`BoundImage <hcloud.images.client.BoundImage>`
|
||||
"""
|
||||
response = self.get_list(name=name, architecture=[architecture])
|
||||
entities = getattr(response, self.results_list_attribute_name)
|
||||
entity = entities[0] if entities else None
|
||||
return entity
|
||||
return self._get_first_by(name=name, architecture=[architecture])
|
||||
|
||||
def update(self, image, description=None, type=None, labels=None):
|
||||
# type:(Image, Optional[str], Optional[str], Optional[Dict[str, str]]) -> BoundImage
|
||||
def update(
|
||||
self,
|
||||
image: Image | BoundImage,
|
||||
description: str | None = None,
|
||||
type: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundImage:
|
||||
"""Updates the Image. You may change the description, convert a Backup image to a Snapshot Image or change the image labels.
|
||||
|
||||
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.images.domain.Image>`
|
||||
|
@ -308,7 +336,7 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundImage <hcloud.images.client.BoundImage>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if description is not None:
|
||||
data.update({"description": description})
|
||||
if type is not None:
|
||||
|
@ -320,8 +348,7 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundImage(self, response["image"])
|
||||
|
||||
def delete(self, image):
|
||||
# type: (Image) -> bool
|
||||
def delete(self, image: Image | BoundImage) -> bool:
|
||||
"""Deletes an Image. Only images of type snapshot and backup can be deleted.
|
||||
|
||||
:param :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.images.domain.Image>`
|
||||
|
@ -331,8 +358,11 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
# Return allays true, because the API does not return an action for it. When an error occurs a APIException will be raised
|
||||
return True
|
||||
|
||||
def change_protection(self, image, delete=None):
|
||||
# type: (Image, Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
image: Image | BoundImage,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of the image. Can only be used on snapshots.
|
||||
|
||||
:param image: :class:`BoundImage <hcloud.images.client.BoundImage>` or :class:`Image <hcloud.images.domain.Image>`
|
||||
|
@ -340,14 +370,12 @@ class ImagesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If true, prevents the snapshot from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/images/{image_id}/actions/change_protection".format(
|
||||
image_id=image.id
|
||||
),
|
||||
url=f"/images/{image.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..servers import BoundServer, Server
|
||||
from .client import BoundImage
|
||||
|
||||
|
||||
class Image(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -67,23 +76,23 @@ class Image(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
type=None,
|
||||
created=None,
|
||||
description=None,
|
||||
image_size=None,
|
||||
disk_size=None,
|
||||
deprecated=None,
|
||||
bound_to=None,
|
||||
os_flavor=None,
|
||||
os_version=None,
|
||||
architecture=None,
|
||||
rapid_deploy=None,
|
||||
created_from=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
status=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
type: str | None = None,
|
||||
created: str | None = None,
|
||||
description: str | None = None,
|
||||
image_size: int | None = None,
|
||||
disk_size: int | None = None,
|
||||
deprecated: str | None = None,
|
||||
bound_to: Server | BoundServer | None = None,
|
||||
os_flavor: str | None = None,
|
||||
os_version: str | None = None,
|
||||
architecture: str | None = None,
|
||||
rapid_deploy: bool | None = None,
|
||||
created_from: Server | BoundServer | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
status: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -117,8 +126,8 @@ class CreateImageResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
action, # type: BoundAction
|
||||
image, # type: BoundImage
|
||||
action: BoundAction,
|
||||
image: BoundImage,
|
||||
):
|
||||
self.action = action
|
||||
self.image = image
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundIso, IsosClient, IsosPageResult # noqa: F401
|
||||
from .domain import Iso # noqa: F401
|
|
@ -1,18 +1,30 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
from warnings import warn
|
||||
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import Iso
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundIso(BoundModelBase):
|
||||
_client: IsosClient
|
||||
|
||||
model = Iso
|
||||
|
||||
|
||||
class IsosClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "isos"
|
||||
class IsosPageResult(NamedTuple):
|
||||
isos: list[BoundIso]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundIso
|
||||
|
||||
class IsosClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundIso:
|
||||
"""Get a specific ISO by its id
|
||||
|
||||
:param id: int
|
||||
|
@ -23,14 +35,13 @@ class IsosClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
architecture=None, # type: Optional[List[str]]
|
||||
include_wildcard_architecture=None, # type: Optional[bool]
|
||||
include_architecture_wildcard=None, # type: Optional[bool]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundIso], Meta]
|
||||
name: str | None = None,
|
||||
architecture: list[str] | None = None,
|
||||
include_wildcard_architecture: bool | None = None,
|
||||
include_architecture_wildcard: bool | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> IsosPageResult:
|
||||
"""Get a list of ISOs
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -56,7 +67,7 @@ class IsosClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
include_architecture_wildcard = include_wildcard_architecture
|
||||
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if architecture is not None:
|
||||
|
@ -70,16 +81,15 @@ class IsosClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
response = self._client.request(url="/isos", method="GET", params=params)
|
||||
isos = [BoundIso(self, iso_data) for iso_data in response["isos"]]
|
||||
return self._add_meta_to_result(isos, response)
|
||||
return IsosPageResult(isos, Meta.parse_meta(response))
|
||||
|
||||
def get_all(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
architecture=None, # type: Optional[List[str]]
|
||||
include_wildcard_architecture=None, # type: Optional[bool]
|
||||
include_architecture_wildcard=None, # type: Optional[bool]
|
||||
):
|
||||
# type: (...) -> List[BoundIso]
|
||||
name: str | None = None,
|
||||
architecture: list[str] | None = None,
|
||||
include_wildcard_architecture: bool | None = None,
|
||||
include_architecture_wildcard: bool | None = None,
|
||||
) -> list[BoundIso]:
|
||||
"""Get all ISOs
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -101,18 +111,18 @@ class IsosClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
include_architecture_wildcard = include_wildcard_architecture
|
||||
|
||||
return super().get_all(
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
name=name,
|
||||
architecture=architecture,
|
||||
include_architecture_wildcard=include_architecture_wildcard,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundIso
|
||||
def get_by_name(self, name: str) -> BoundIso | None:
|
||||
"""Get iso by name
|
||||
|
||||
:param name: str
|
||||
Used to get iso by name.
|
||||
:return: :class:`BoundIso <hcloud.isos.client.BoundIso>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
|
||||
class Iso(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -27,12 +29,12 @@ class Iso(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
type=None,
|
||||
architecture=None,
|
||||
description=None,
|
||||
deprecated=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
type: str | None = None,
|
||||
architecture: str | None = None,
|
||||
description: str | None = None,
|
||||
deprecated: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundLoadBalancerType,
|
||||
LoadBalancerTypesClient,
|
||||
LoadBalancerTypesPageResult,
|
||||
)
|
||||
from .domain import LoadBalancerType # noqa: F401
|
|
@ -1,31 +1,46 @@
|
|||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import LoadBalancerType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundLoadBalancerType(BoundModelBase):
|
||||
_client: LoadBalancerTypesClient
|
||||
|
||||
model = LoadBalancerType
|
||||
|
||||
|
||||
class LoadBalancerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "load_balancer_types"
|
||||
class LoadBalancerTypesPageResult(NamedTuple):
|
||||
load_balancer_types: list[BoundLoadBalancerType]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> load_balancer_types.client.BoundLoadBalancerType
|
||||
|
||||
class LoadBalancerTypesClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundLoadBalancerType:
|
||||
"""Returns a specific Load Balancer Type.
|
||||
|
||||
:param id: int
|
||||
:return: :class:`BoundLoadBalancerType <hcloud.load_balancer_type.client.BoundLoadBalancerType>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/load_balancer_types/{load_balancer_type_id}".format(
|
||||
load_balancer_type_id=id
|
||||
),
|
||||
url=f"/load_balancer_types/{id}",
|
||||
method="GET",
|
||||
)
|
||||
return BoundLoadBalancerType(self, response["load_balancer_type"])
|
||||
|
||||
def get_list(self, name=None, page=None, per_page=None):
|
||||
# type: (Optional[str], Optional[int], Optional[int]) -> PageResults[List[BoundLoadBalancerType], Meta]
|
||||
def get_list(
|
||||
self,
|
||||
name: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> LoadBalancerTypesPageResult:
|
||||
"""Get a list of Load Balancer types
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -36,7 +51,7 @@ class LoadBalancerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundLoadBalancerType <hcloud.load_balancer_types.client.BoundLoadBalancerType>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if page is not None:
|
||||
|
@ -51,24 +66,24 @@ class LoadBalancerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundLoadBalancerType(self, load_balancer_type_data)
|
||||
for load_balancer_type_data in response["load_balancer_types"]
|
||||
]
|
||||
return self._add_meta_to_result(load_balancer_types, response)
|
||||
return LoadBalancerTypesPageResult(
|
||||
load_balancer_types, Meta.parse_meta(response)
|
||||
)
|
||||
|
||||
def get_all(self, name=None):
|
||||
# type: (Optional[str]) -> List[BoundLoadBalancerType]
|
||||
def get_all(self, name: str | None = None) -> list[BoundLoadBalancerType]:
|
||||
"""Get all Load Balancer types
|
||||
|
||||
:param name: str (optional)
|
||||
Can be used to filter Load Balancer type by their name.
|
||||
:return: List[:class:`BoundLoadBalancerType <hcloud.load_balancer_types.client.BoundLoadBalancerType>`]
|
||||
"""
|
||||
return super().get_all(name=name)
|
||||
return self._iter_pages(self.get_list, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundLoadBalancerType
|
||||
def get_by_name(self, name: str) -> BoundLoadBalancerType | None:
|
||||
"""Get Load Balancer type by name
|
||||
|
||||
:param name: str
|
||||
Used to get Load Balancer type by name.
|
||||
:return: :class:`BoundLoadBalancerType <hcloud.load_balancer_types.client.BoundLoadBalancerType>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
|
||||
class LoadBalancerType(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -36,14 +38,14 @@ class LoadBalancerType(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
description=None,
|
||||
max_connections=None,
|
||||
max_services=None,
|
||||
max_targets=None,
|
||||
max_assigned_certificates=None,
|
||||
prices=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
max_connections: int | None = None,
|
||||
max_services: int | None = None,
|
||||
max_targets: int | None = None,
|
||||
max_assigned_certificates: int | None = None,
|
||||
prices: dict | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundLoadBalancer,
|
||||
LoadBalancersClient,
|
||||
LoadBalancersPageResult,
|
||||
)
|
||||
from .domain import ( # noqa: F401
|
||||
CreateLoadBalancerResponse,
|
||||
IPv4Address,
|
||||
IPv6Network,
|
||||
LoadBalancer,
|
||||
LoadBalancerAlgorithm,
|
||||
LoadBalancerHealtCheckHttp,
|
||||
LoadBalancerHealthCheck,
|
||||
LoadBalancerService,
|
||||
LoadBalancerServiceHttp,
|
||||
LoadBalancerTarget,
|
||||
LoadBalancerTargetIP,
|
||||
LoadBalancerTargetLabelSelector,
|
||||
PrivateNet,
|
||||
PublicNetwork,
|
||||
)
|
|
@ -1,11 +1,14 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..certificates.client import BoundCertificate
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from ..load_balancer_types.client import BoundLoadBalancerType
|
||||
from ..locations.client import BoundLocation
|
||||
from ..networks.client import BoundNetwork
|
||||
from ..servers.client import BoundServer
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..certificates import BoundCertificate
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from ..load_balancer_types import BoundLoadBalancerType
|
||||
from ..locations import BoundLocation
|
||||
from ..networks import BoundNetwork
|
||||
from ..servers import BoundServer
|
||||
from .domain import (
|
||||
CreateLoadBalancerResponse,
|
||||
IPv4Address,
|
||||
|
@ -23,11 +26,19 @@ from .domain import (
|
|||
PublicNetwork,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
from ..load_balancer_types import LoadBalancerType
|
||||
from ..locations import Location
|
||||
from ..networks import Network
|
||||
|
||||
|
||||
class BoundLoadBalancer(BoundModelBase):
|
||||
_client: LoadBalancersClient
|
||||
|
||||
model = LoadBalancer
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
def __init__(self, client: LoadBalancersClient, data: dict, complete: bool = True):
|
||||
algorithm = data.get("algorithm")
|
||||
if algorithm:
|
||||
data["algorithm"] = LoadBalancerAlgorithm(type=algorithm["type"])
|
||||
|
@ -131,8 +142,11 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def update(self, name=None, labels=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]]) -> BoundLoadBalancer
|
||||
def update(
|
||||
self,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundLoadBalancer:
|
||||
"""Updates a Load Balancer. You can update a Load Balancers name and a Load Balancers labels.
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -143,16 +157,20 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, name, labels)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> BoundAction
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a Load Balancer.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction, Meta]]
|
||||
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 action objects for a Load Balancer.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -167,8 +185,11 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Load Balancer.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -179,8 +200,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def add_service(self, service):
|
||||
# type: (LoadBalancerService) -> List[BoundAction]
|
||||
def add_service(self, service: LoadBalancerService) -> BoundAction:
|
||||
"""Adds a service to a Load Balancer.
|
||||
|
||||
:param service: :class:`LoadBalancerService <hcloud.load_balancers.domain.LoadBalancerService>`
|
||||
|
@ -189,8 +209,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.add_service(self, service=service)
|
||||
|
||||
def update_service(self, service):
|
||||
# type: (LoadBalancerService) -> List[BoundAction]
|
||||
def update_service(self, service: LoadBalancerService) -> BoundAction:
|
||||
"""Updates a service of an Load Balancer.
|
||||
|
||||
:param service: :class:`LoadBalancerService <hcloud.load_balancers.domain.LoadBalancerService>`
|
||||
|
@ -199,8 +218,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.update_service(self, service=service)
|
||||
|
||||
def delete_service(self, service):
|
||||
# type: (LoadBalancerService) -> List[BoundAction]
|
||||
def delete_service(self, service: LoadBalancerService) -> BoundAction:
|
||||
"""Deletes a service from a Load Balancer.
|
||||
|
||||
:param service: :class:`LoadBalancerService <hcloud.load_balancers.domain.LoadBalancerService>`
|
||||
|
@ -209,8 +227,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.delete_service(self, service)
|
||||
|
||||
def add_target(self, target):
|
||||
# type: (LoadBalancerTarget) -> List[BoundAction]
|
||||
def add_target(self, target: LoadBalancerTarget) -> BoundAction:
|
||||
"""Adds a target to a Load Balancer.
|
||||
|
||||
:param target: :class:`LoadBalancerTarget <hcloud.load_balancers.domain.LoadBalancerTarget>`
|
||||
|
@ -219,8 +236,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.add_target(self, target)
|
||||
|
||||
def remove_target(self, target):
|
||||
# type: (LoadBalancerTarget) -> List[BoundAction]
|
||||
def remove_target(self, target: LoadBalancerTarget) -> BoundAction:
|
||||
"""Removes a target from a Load Balancer.
|
||||
|
||||
:param target: :class:`LoadBalancerTarget <hcloud.load_balancers.domain.LoadBalancerTarget>`
|
||||
|
@ -229,8 +245,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.remove_target(self, target)
|
||||
|
||||
def change_algorithm(self, algorithm):
|
||||
# type: (LoadBalancerAlgorithm) -> List[BoundAction]
|
||||
def change_algorithm(self, algorithm: LoadBalancerAlgorithm) -> BoundAction:
|
||||
"""Changes the algorithm used by the Load Balancer
|
||||
|
||||
:param algorithm: :class:`LoadBalancerAlgorithm <hcloud.load_balancers.domain.LoadBalancerAlgorithm>`
|
||||
|
@ -239,8 +254,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_algorithm(self, algorithm)
|
||||
|
||||
def change_dns_ptr(self, ip, dns_ptr):
|
||||
# type: (str, str) -> BoundAction
|
||||
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.
|
||||
|
||||
:param ip: str
|
||||
|
@ -251,8 +265,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_dns_ptr(self, ip, dns_ptr)
|
||||
|
||||
def change_protection(self, delete):
|
||||
# type: (LoadBalancerService) -> List[BoundAction]
|
||||
def change_protection(self, delete: bool) -> BoundAction:
|
||||
"""Changes the protection configuration of a Load Balancer.
|
||||
|
||||
:param delete: boolean
|
||||
|
@ -261,8 +274,11 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_protection(self, delete)
|
||||
|
||||
def attach_to_network(self, network, ip=None):
|
||||
# type: (Union[Network,BoundNetwork],Optional[str]) -> BoundAction
|
||||
def attach_to_network(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
ip: str | None = None,
|
||||
) -> BoundAction:
|
||||
"""Attaches a Load Balancer to a Network
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -272,8 +288,7 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.attach_to_network(self, network, ip)
|
||||
|
||||
def detach_from_network(self, network):
|
||||
# type: ( Union[Network,BoundNetwork]) -> BoundAction
|
||||
def detach_from_network(self, network: Network | BoundNetwork) -> BoundAction:
|
||||
"""Detaches a Load Balancer from a Network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -281,24 +296,24 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
"""
|
||||
return self._client.detach_from_network(self, network)
|
||||
|
||||
def enable_public_interface(self):
|
||||
# type: () -> BoundAction
|
||||
def enable_public_interface(self) -> BoundAction:
|
||||
"""Enables the public interface of a Load Balancer.
|
||||
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
return self._client.enable_public_interface(self)
|
||||
|
||||
def disable_public_interface(self):
|
||||
# type: () -> BoundAction
|
||||
def disable_public_interface(self) -> BoundAction:
|
||||
"""Disables the public interface of a Load Balancer.
|
||||
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
return self._client.disable_public_interface(self)
|
||||
|
||||
def change_type(self, load_balancer_type):
|
||||
# type: (Union[LoadBalancerType,BoundLoadBalancerType]) -> BoundAction
|
||||
def change_type(
|
||||
self,
|
||||
load_balancer_type: LoadBalancerType | BoundLoadBalancerType,
|
||||
) -> BoundAction:
|
||||
"""Changes the type of a Load Balancer.
|
||||
|
||||
:param load_balancer_type: :class:`BoundLoadBalancerType <hcloud.load_balancer_types.client.BoundLoadBalancerType>` or :class:`LoadBalancerType <hcloud.load_balancer_types.domain.LoadBalancerType>`
|
||||
|
@ -308,11 +323,15 @@ class BoundLoadBalancer(BoundModelBase):
|
|||
return self._client.change_type(self, load_balancer_type)
|
||||
|
||||
|
||||
class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "load_balancers"
|
||||
class LoadBalancersPageResult(NamedTuple):
|
||||
load_balancers: list[BoundLoadBalancer]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundLoadBalancer
|
||||
|
||||
class LoadBalancersClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundLoadBalancer:
|
||||
"""Get a specific Load Balancer
|
||||
|
||||
:param id: int
|
||||
|
@ -326,12 +345,11 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundLoadBalancer], Meta]
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> LoadBalancersPageResult:
|
||||
"""Get a list of Load Balancers from this account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -344,7 +362,7 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if label_selector is not None:
|
||||
|
@ -358,14 +376,17 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
url="/load_balancers", method="GET", params=params
|
||||
)
|
||||
|
||||
ass_load_balancers = [
|
||||
load_balancers = [
|
||||
BoundLoadBalancer(self, load_balancer_data)
|
||||
for load_balancer_data in response["load_balancers"]
|
||||
]
|
||||
return self._add_meta_to_result(ass_load_balancers, response)
|
||||
return LoadBalancersPageResult(load_balancers, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None, label_selector=None):
|
||||
# type: (Optional[str], Optional[str]) -> List[BoundLoadBalancer]
|
||||
def get_all(
|
||||
self,
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
) -> list[BoundLoadBalancer]:
|
||||
"""Get all Load Balancers from this account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -374,32 +395,30 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter Load Balancers by labels. The response will only contain Load Balancers matching the label selector.
|
||||
:return: List[:class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>`]
|
||||
"""
|
||||
return super().get_all(name=name, label_selector=label_selector)
|
||||
return self._iter_pages(self.get_list, name=name, label_selector=label_selector)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundLoadBalancer
|
||||
def get_by_name(self, name: str) -> BoundLoadBalancer | None:
|
||||
"""Get Load Balancer by name
|
||||
|
||||
:param name: str
|
||||
Used to get Load Balancer by name.
|
||||
:return: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
name, # type: str
|
||||
load_balancer_type, # type: LoadBalancerType
|
||||
algorithm=None, # type: Optional[LoadBalancerAlgorithm]
|
||||
services=None, # type: Optional[List[LoadBalancerService]]
|
||||
targets=None, # type: Optional[List[LoadBalancerTarget]]
|
||||
labels=None, # type: Optional[Dict[str, str]]
|
||||
location=None, # type: Optional[Location]
|
||||
network_zone=None, # type: Optional[str]
|
||||
public_interface=None, # type: Optional[bool]
|
||||
network=None, # type: Optional[Union[Network,BoundNetwork]]
|
||||
):
|
||||
# type: (...) -> CreateLoadBalancerResponse
|
||||
name: str,
|
||||
load_balancer_type: LoadBalancerType | BoundLoadBalancerType,
|
||||
algorithm: LoadBalancerAlgorithm | None = None,
|
||||
services: list[LoadBalancerService] | None = None,
|
||||
targets: list[LoadBalancerTarget] | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
location: Location | BoundLocation | None = None,
|
||||
network_zone: str | None = None,
|
||||
public_interface: bool | None = None,
|
||||
network: Network | BoundNetwork | None = None,
|
||||
) -> CreateLoadBalancerResponse:
|
||||
"""Creates a Load Balancer .
|
||||
|
||||
:param name: str
|
||||
|
@ -424,7 +443,10 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Adds the Load Balancer to a Network
|
||||
:return: :class:`CreateLoadBalancerResponse <hcloud.load_balancers.domain.CreateLoadBalancerResponse>`
|
||||
"""
|
||||
data = {"name": name, "load_balancer_type": load_balancer_type.id_or_name}
|
||||
data: dict[str, Any] = {
|
||||
"name": name,
|
||||
"load_balancer_type": load_balancer_type.id_or_name,
|
||||
}
|
||||
if network is not None:
|
||||
data["network"] = network.id
|
||||
if public_interface is not None:
|
||||
|
@ -434,30 +456,9 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
if algorithm is not None:
|
||||
data["algorithm"] = {"type": algorithm.type}
|
||||
if services is not None:
|
||||
service_list = []
|
||||
for service in services:
|
||||
service_list.append(self.get_service_parameters(service))
|
||||
data["services"] = service_list
|
||||
|
||||
data["services"] = [service.to_payload() for service in services]
|
||||
if targets is not None:
|
||||
target_list = []
|
||||
for target in targets:
|
||||
target_data = {
|
||||
"type": target.type,
|
||||
"use_private_ip": target.use_private_ip,
|
||||
}
|
||||
if target.type == "server":
|
||||
target_data["server"] = {"id": target.server.id}
|
||||
elif target.type == "label_selector":
|
||||
target_data["label_selector"] = {
|
||||
"selector": target.label_selector.selector
|
||||
}
|
||||
elif target.type == "ip":
|
||||
target_data["ip"] = {"ip": target.ip.ip}
|
||||
target_list.append(target_data)
|
||||
|
||||
data["targets"] = target_list
|
||||
|
||||
data["targets"] = [target.to_payload() for target in targets]
|
||||
if network_zone is not None:
|
||||
data["network_zone"] = network_zone
|
||||
if location is not None:
|
||||
|
@ -470,8 +471,12 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
action=BoundAction(self._client.actions, response["action"]),
|
||||
)
|
||||
|
||||
def update(self, load_balancer, name=None, labels=None):
|
||||
# type:(LoadBalancer, Optional[str], Optional[Dict[str, str]]) -> BoundLoadBalancer
|
||||
def update(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundLoadBalancer:
|
||||
"""Updates a LoadBalancer. You can update a LoadBalancer’s name and a LoadBalancer’s labels.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -481,39 +486,38 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
data.update({"name": name})
|
||||
if labels is not None:
|
||||
data.update({"labels": labels})
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}",
|
||||
method="PUT",
|
||||
json=data,
|
||||
)
|
||||
return BoundLoadBalancer(self, response["load_balancer"])
|
||||
|
||||
def delete(self, load_balancer):
|
||||
# type: (LoadBalancer) -> BoundAction
|
||||
def delete(self, load_balancer: LoadBalancer | BoundLoadBalancer) -> bool:
|
||||
"""Deletes a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
:return: boolean
|
||||
"""
|
||||
self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}",
|
||||
method="DELETE",
|
||||
)
|
||||
return True
|
||||
|
||||
def get_actions_list(
|
||||
self, load_balancer, status=None, sort=None, page=None, per_page=None
|
||||
):
|
||||
# type: (LoadBalancer, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta]
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -527,7 +531,7 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -538,9 +542,7 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
params["per_page"] = per_page
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions",
|
||||
method="GET",
|
||||
params=params,
|
||||
)
|
||||
|
@ -548,10 +550,14 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(self, load_balancer, status=None, sort=None):
|
||||
# type: (LoadBalancer, Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -561,10 +567,18 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
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 <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(load_balancer, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
load_balancer,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def add_service(self, load_balancer, service):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerService) -> List[BoundAction]
|
||||
def add_service(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
service: LoadBalancerService,
|
||||
) -> BoundAction:
|
||||
"""Adds a service to a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -572,84 +586,20 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerService you want to add to the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = self.get_service_parameters(service)
|
||||
data: dict[str, Any] = service.to_payload()
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/add_service".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/add_service",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def get_service_parameters(self, service):
|
||||
data = {}
|
||||
if service.protocol is not None:
|
||||
data["protocol"] = service.protocol
|
||||
if service.listen_port is not None:
|
||||
data["listen_port"] = service.listen_port
|
||||
if service.destination_port is not None:
|
||||
data["destination_port"] = service.destination_port
|
||||
if service.proxyprotocol is not None:
|
||||
data["proxyprotocol"] = service.proxyprotocol
|
||||
if service.http is not None:
|
||||
data["http"] = {}
|
||||
if service.http.cookie_name is not None:
|
||||
data["http"]["cookie_name"] = service.http.cookie_name
|
||||
if service.http.cookie_lifetime is not None:
|
||||
data["http"]["cookie_lifetime"] = service.http.cookie_lifetime
|
||||
if service.http.redirect_http is not None:
|
||||
data["http"]["redirect_http"] = service.http.redirect_http
|
||||
if service.http.sticky_sessions is not None:
|
||||
data["http"]["sticky_sessions"] = service.http.sticky_sessions
|
||||
certificate_ids = []
|
||||
for certificate in service.http.certificates:
|
||||
certificate_ids.append(certificate.id)
|
||||
data["http"]["certificates"] = certificate_ids
|
||||
if service.health_check is not None:
|
||||
data["health_check"] = {
|
||||
"protocol": service.health_check.protocol,
|
||||
"port": service.health_check.port,
|
||||
"interval": service.health_check.interval,
|
||||
"timeout": service.health_check.timeout,
|
||||
"retries": service.health_check.retries,
|
||||
}
|
||||
data["health_check"] = {}
|
||||
if service.health_check.protocol is not None:
|
||||
data["health_check"]["protocol"] = service.health_check.protocol
|
||||
if service.health_check.port is not None:
|
||||
data["health_check"]["port"] = service.health_check.port
|
||||
if service.health_check.interval is not None:
|
||||
data["health_check"]["interval"] = service.health_check.interval
|
||||
if service.health_check.timeout is not None:
|
||||
data["health_check"]["timeout"] = service.health_check.timeout
|
||||
if service.health_check.retries is not None:
|
||||
data["health_check"]["retries"] = service.health_check.retries
|
||||
if service.health_check.http is not None:
|
||||
data["health_check"]["http"] = {}
|
||||
if service.health_check.http.domain is not None:
|
||||
data["health_check"]["http"][
|
||||
"domain"
|
||||
] = service.health_check.http.domain
|
||||
if service.health_check.http.path is not None:
|
||||
data["health_check"]["http"][
|
||||
"path"
|
||||
] = service.health_check.http.path
|
||||
if service.health_check.http.response is not None:
|
||||
data["health_check"]["http"][
|
||||
"response"
|
||||
] = service.health_check.http.response
|
||||
if service.health_check.http.status_codes is not None:
|
||||
data["health_check"]["http"][
|
||||
"status_codes"
|
||||
] = service.health_check.http.status_codes
|
||||
if service.health_check.http.tls is not None:
|
||||
data["health_check"]["http"]["tls"] = service.health_check.http.tls
|
||||
return data
|
||||
|
||||
def update_service(self, load_balancer, service):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerService) -> List[BoundAction]
|
||||
def update_service(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
service: LoadBalancerService,
|
||||
) -> BoundAction:
|
||||
"""Updates a service of an Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -657,18 +607,19 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerService with updated values within for the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = self.get_service_parameters(service)
|
||||
data: dict[str, Any] = service.to_payload()
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/update_service".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/update_service",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def delete_service(self, load_balancer, service):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerService) -> List[BoundAction]
|
||||
def delete_service(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
service: LoadBalancerService,
|
||||
) -> BoundAction:
|
||||
"""Deletes a service from a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -676,19 +627,20 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerService you want to delete from the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"listen_port": service.listen_port}
|
||||
data: dict[str, Any] = {"listen_port": service.listen_port}
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/delete_service".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/delete_service",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def add_target(self, load_balancer, target):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerTarget) -> List[BoundAction]
|
||||
def add_target(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
target: LoadBalancerTarget,
|
||||
) -> BoundAction:
|
||||
"""Adds a target to a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -696,25 +648,20 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerTarget you want to add to the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"type": target.type, "use_private_ip": target.use_private_ip}
|
||||
if target.type == "server":
|
||||
data["server"] = {"id": target.server.id}
|
||||
elif target.type == "label_selector":
|
||||
data["label_selector"] = {"selector": target.label_selector.selector}
|
||||
elif target.type == "ip":
|
||||
data["ip"] = {"ip": target.ip.ip}
|
||||
data: dict[str, Any] = target.to_payload()
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/add_target".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/add_target",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def remove_target(self, load_balancer, target):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerTarget) -> List[BoundAction]
|
||||
def remove_target(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
target: LoadBalancerTarget,
|
||||
) -> BoundAction:
|
||||
"""Removes a target from a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -722,25 +669,22 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerTarget you want to remove from the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"type": target.type}
|
||||
if target.type == "server":
|
||||
data["server"] = {"id": target.server.id}
|
||||
elif target.type == "label_selector":
|
||||
data["label_selector"] = {"selector": target.label_selector.selector}
|
||||
elif target.type == "ip":
|
||||
data["ip"] = {"ip": target.ip.ip}
|
||||
data: dict[str, Any] = target.to_payload()
|
||||
# Do not send use_private_ip on remove_target
|
||||
data.pop("use_private_ip", None)
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/remove_target".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/remove_target",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_algorithm(self, load_balancer, algorithm):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], Optional[bool]) -> BoundAction
|
||||
def change_algorithm(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
algorithm: LoadBalancerAlgorithm,
|
||||
) -> BoundAction:
|
||||
"""Changes the algorithm used by the Load Balancer
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -748,19 +692,21 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The LoadBalancerSubnet you want to add to the Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"type": algorithm.type}
|
||||
data: dict[str, Any] = {"type": algorithm.type}
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/change_algorithm".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/change_algorithm",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_dns_ptr(self, load_balancer, ip, dns_ptr):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], str, str) -> BoundAction
|
||||
def change_dns_ptr(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
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.
|
||||
|
||||
:param ip: str
|
||||
|
@ -771,16 +717,17 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
"""
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/change_dns_ptr".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/change_dns_ptr",
|
||||
method="POST",
|
||||
json={"ip": ip, "dns_ptr": dns_ptr},
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_protection(self, load_balancer, delete=None):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -788,14 +735,12 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If True, prevents the Load Balancer from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/change_protection".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
|
@ -803,10 +748,10 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def attach_to_network(
|
||||
self,
|
||||
load_balancer, # type: Union[LoadBalancer, BoundLoadBalancer]
|
||||
network, # type: Union[Network, BoundNetwork]
|
||||
ip=None, # type: Optional[str]
|
||||
):
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
network: Network | BoundNetwork,
|
||||
ip: str | None = None,
|
||||
) -> BoundAction:
|
||||
"""Attach a Load Balancer to a Network.
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -815,39 +760,40 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
IP to request to be assigned to this Load Balancer
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"network": network.id}
|
||||
data: dict[str, Any] = {"network": network.id}
|
||||
if ip is not None:
|
||||
data.update({"ip": ip})
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/attach_to_network".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/attach_to_network",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def detach_from_network(self, load_balancer, network):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer], Union[Network,BoundNetwork]) -> BoundAction
|
||||
def detach_from_network(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
network: Network | BoundNetwork,
|
||||
) -> BoundAction:
|
||||
"""Detaches a Load Balancer from a Network.
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"network": network.id}
|
||||
data: dict[str, Any] = {"network": network.id}
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/detach_from_network".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/detach_from_network",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def enable_public_interface(self, load_balancer):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer]) -> BoundAction
|
||||
def enable_public_interface(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
) -> BoundAction:
|
||||
"""Enables the public interface of a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -856,15 +802,15 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
"""
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/enable_public_interface".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/enable_public_interface",
|
||||
method="POST",
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def disable_public_interface(self, load_balancer):
|
||||
# type: (Union[LoadBalancer, BoundLoadBalancer]) -> BoundAction
|
||||
def disable_public_interface(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
) -> BoundAction:
|
||||
"""Disables the public interface of a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:` <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -873,15 +819,16 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
"""
|
||||
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/disable_public_interface".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/disable_public_interface",
|
||||
method="POST",
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_type(self, load_balancer, load_balancer_type):
|
||||
# type: ([LoadBalancer, BoundLoadBalancer], [LoadBalancerType, BoundLoadBalancerType]) ->BoundAction
|
||||
def change_type(
|
||||
self,
|
||||
load_balancer: LoadBalancer | BoundLoadBalancer,
|
||||
load_balancer_type: LoadBalancerType | BoundLoadBalancerType,
|
||||
) -> BoundAction:
|
||||
"""Changes the type of a Load Balancer.
|
||||
|
||||
:param load_balancer: :class:`BoundLoadBalancer <hcloud.load_balancers.client.BoundLoadBalancer>` or :class:`LoadBalancer <hcloud.load_balancers.domain.LoadBalancer>`
|
||||
|
@ -889,11 +836,9 @@ class LoadBalancersClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Load Balancer type the Load Balancer should migrate to
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"load_balancer_type": load_balancer_type.id_or_name}
|
||||
data: dict[str, Any] = {"load_balancer_type": load_balancer_type.id_or_name}
|
||||
response = self._client.request(
|
||||
url="/load_balancers/{load_balancer_id}/actions/change_type".format(
|
||||
load_balancer_id=load_balancer.id
|
||||
),
|
||||
url=f"/load_balancers/{load_balancer.id}/actions/change_type",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
|
|
|
@ -1,9 +1,22 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..certificates import BoundCertificate
|
||||
from ..load_balancer_types import BoundLoadBalancerType
|
||||
from ..locations import BoundLocation
|
||||
from ..networks import BoundNetwork
|
||||
from ..servers import BoundServer
|
||||
from .client import BoundLoadBalancer
|
||||
|
||||
|
||||
class LoadBalancer(BaseDomain):
|
||||
|
@ -61,21 +74,21 @@ class LoadBalancer(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
name=None,
|
||||
public_net=None,
|
||||
private_net=None,
|
||||
location=None,
|
||||
algorithm=None,
|
||||
services=None,
|
||||
load_balancer_type=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
targets=None,
|
||||
created=None,
|
||||
outgoing_traffic=None,
|
||||
ingoing_traffic=None,
|
||||
included_traffic=None,
|
||||
id: int,
|
||||
name: str | None = None,
|
||||
public_net: PublicNetwork | None = None,
|
||||
private_net: PrivateNet | None = None,
|
||||
location: BoundLocation | None = None,
|
||||
algorithm: LoadBalancerAlgorithm | None = None,
|
||||
services: list[LoadBalancerService] | None = None,
|
||||
load_balancer_type: BoundLoadBalancerType | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
targets: list[LoadBalancerTarget] | None = None,
|
||||
created: str | None = None,
|
||||
outgoing_traffic: int | None = None,
|
||||
ingoing_traffic: int | None = None,
|
||||
included_traffic: int | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -113,12 +126,12 @@ class LoadBalancerService(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
protocol=None,
|
||||
listen_port=None,
|
||||
destination_port=None,
|
||||
proxyprotocol=None,
|
||||
health_check=None,
|
||||
http=None,
|
||||
protocol: str | None = None,
|
||||
listen_port: int | None = None,
|
||||
destination_port: int | None = None,
|
||||
proxyprotocol: bool | None = None,
|
||||
health_check: LoadBalancerHealthCheck | None = None,
|
||||
http: LoadBalancerServiceHttp | None = None,
|
||||
):
|
||||
self.protocol = protocol
|
||||
self.listen_port = listen_port
|
||||
|
@ -127,6 +140,74 @@ class LoadBalancerService(BaseDomain):
|
|||
self.health_check = health_check
|
||||
self.http = http
|
||||
|
||||
def to_payload(self) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {}
|
||||
|
||||
if self.protocol is not None:
|
||||
payload["protocol"] = self.protocol
|
||||
if self.listen_port is not None:
|
||||
payload["listen_port"] = self.listen_port
|
||||
if self.destination_port is not None:
|
||||
payload["destination_port"] = self.destination_port
|
||||
if self.proxyprotocol is not None:
|
||||
payload["proxyprotocol"] = self.proxyprotocol
|
||||
|
||||
if self.http is not None:
|
||||
http: dict[str, Any] = {}
|
||||
if self.http.cookie_name is not None:
|
||||
http["cookie_name"] = self.http.cookie_name
|
||||
if self.http.cookie_lifetime is not None:
|
||||
http["cookie_lifetime"] = self.http.cookie_lifetime
|
||||
if self.http.redirect_http is not None:
|
||||
http["redirect_http"] = self.http.redirect_http
|
||||
if self.http.sticky_sessions is not None:
|
||||
http["sticky_sessions"] = self.http.sticky_sessions
|
||||
|
||||
http["certificates"] = [
|
||||
certificate.id for certificate in self.http.certificates or []
|
||||
]
|
||||
|
||||
payload["http"] = http
|
||||
|
||||
if self.health_check is not None:
|
||||
health_check: dict[str, Any] = {
|
||||
"protocol": self.health_check.protocol,
|
||||
"port": self.health_check.port,
|
||||
"interval": self.health_check.interval,
|
||||
"timeout": self.health_check.timeout,
|
||||
"retries": self.health_check.retries,
|
||||
}
|
||||
if self.health_check.protocol is not None:
|
||||
health_check["protocol"] = self.health_check.protocol
|
||||
if self.health_check.port is not None:
|
||||
health_check["port"] = self.health_check.port
|
||||
if self.health_check.interval is not None:
|
||||
health_check["interval"] = self.health_check.interval
|
||||
if self.health_check.timeout is not None:
|
||||
health_check["timeout"] = self.health_check.timeout
|
||||
if self.health_check.retries is not None:
|
||||
health_check["retries"] = self.health_check.retries
|
||||
|
||||
if self.health_check.http is not None:
|
||||
health_check_http: dict[str, Any] = {}
|
||||
if self.health_check.http.domain is not None:
|
||||
health_check_http["domain"] = self.health_check.http.domain
|
||||
if self.health_check.http.path is not None:
|
||||
health_check_http["path"] = self.health_check.http.path
|
||||
if self.health_check.http.response is not None:
|
||||
health_check_http["response"] = self.health_check.http.response
|
||||
if self.health_check.http.status_codes is not None:
|
||||
health_check_http[
|
||||
"status_codes"
|
||||
] = self.health_check.http.status_codes
|
||||
if self.health_check.http.tls is not None:
|
||||
health_check_http["tls"] = self.health_check.http.tls
|
||||
|
||||
health_check["http"] = health_check_http
|
||||
|
||||
payload["health_check"] = health_check
|
||||
return payload
|
||||
|
||||
|
||||
class LoadBalancerServiceHttp(BaseDomain):
|
||||
"""LoadBalancerServiceHttp Domain
|
||||
|
@ -145,11 +226,11 @@ class LoadBalancerServiceHttp(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
cookie_name=None,
|
||||
cookie_lifetime=None,
|
||||
certificates=None,
|
||||
redirect_http=None,
|
||||
sticky_sessions=None,
|
||||
cookie_name: str | None = None,
|
||||
cookie_lifetime: str | None = None,
|
||||
certificates: list[BoundCertificate] | None = None,
|
||||
redirect_http: bool | None = None,
|
||||
sticky_sessions: bool | None = None,
|
||||
):
|
||||
self.cookie_name = cookie_name
|
||||
self.cookie_lifetime = cookie_lifetime
|
||||
|
@ -177,12 +258,12 @@ class LoadBalancerHealthCheck(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
protocol=None,
|
||||
port=None,
|
||||
interval=None,
|
||||
timeout=None,
|
||||
retries=None,
|
||||
http=None,
|
||||
protocol: str | None = None,
|
||||
port: int | None = None,
|
||||
interval: int | None = None,
|
||||
timeout: int | None = None,
|
||||
retries: int | None = None,
|
||||
http: LoadBalancerHealtCheckHttp | None = None,
|
||||
):
|
||||
self.protocol = protocol
|
||||
self.port = port
|
||||
|
@ -208,7 +289,12 @@ class LoadBalancerHealtCheckHttp(BaseDomain):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, domain=None, path=None, response=None, status_codes=None, tls=None
|
||||
self,
|
||||
domain: str | None = None,
|
||||
path: str | None = None,
|
||||
response: str | None = None,
|
||||
status_codes: list | None = None,
|
||||
tls: bool | None = None,
|
||||
):
|
||||
self.domain = domain
|
||||
self.path = path
|
||||
|
@ -233,7 +319,12 @@ class LoadBalancerTarget(BaseDomain):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, type=None, server=None, label_selector=None, ip=None, use_private_ip=None
|
||||
self,
|
||||
type: str | None = None,
|
||||
server: BoundServer | None = None,
|
||||
label_selector: LoadBalancerTargetLabelSelector | None = None,
|
||||
ip: LoadBalancerTargetIP | None = None,
|
||||
use_private_ip: bool | None = None,
|
||||
):
|
||||
self.type = type
|
||||
self.server = server
|
||||
|
@ -241,6 +332,30 @@ class LoadBalancerTarget(BaseDomain):
|
|||
self.ip = ip
|
||||
self.use_private_ip = use_private_ip
|
||||
|
||||
def to_payload(self) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {
|
||||
"type": self.type,
|
||||
}
|
||||
if self.use_private_ip is not None:
|
||||
payload["use_private_ip"] = self.use_private_ip
|
||||
|
||||
if self.type == "server":
|
||||
if self.server is None:
|
||||
raise ValueError(f"server is not defined in target {self!r}")
|
||||
payload["server"] = {"id": self.server.id}
|
||||
|
||||
elif self.type == "label_selector":
|
||||
if self.label_selector is None:
|
||||
raise ValueError(f"label_selector is not defined in target {self!r}")
|
||||
payload["label_selector"] = {"selector": self.label_selector.selector}
|
||||
|
||||
elif self.type == "ip":
|
||||
if self.ip is None:
|
||||
raise ValueError(f"ip is not defined in target {self!r}")
|
||||
payload["ip"] = {"ip": self.ip.ip}
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
class LoadBalancerTargetLabelSelector(BaseDomain):
|
||||
"""LoadBalancerTargetLabelSelector Domain
|
||||
|
@ -248,7 +363,7 @@ class LoadBalancerTargetLabelSelector(BaseDomain):
|
|||
:param selector: str Target label selector
|
||||
"""
|
||||
|
||||
def __init__(self, selector=None):
|
||||
def __init__(self, selector: str | None = None):
|
||||
self.selector = selector
|
||||
|
||||
|
||||
|
@ -258,7 +373,7 @@ class LoadBalancerTargetIP(BaseDomain):
|
|||
:param ip: str Target IP
|
||||
"""
|
||||
|
||||
def __init__(self, ip=None):
|
||||
def __init__(self, ip: str | None = None):
|
||||
self.ip = ip
|
||||
|
||||
|
||||
|
@ -269,7 +384,7 @@ class LoadBalancerAlgorithm(BaseDomain):
|
|||
Algorithm of the Load Balancer. Choices: round_robin, least_connections
|
||||
"""
|
||||
|
||||
def __init__(self, type=None):
|
||||
def __init__(self, type: str | None = None):
|
||||
self.type = type
|
||||
|
||||
|
||||
|
@ -285,9 +400,9 @@ class PublicNetwork(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ipv4, # type: IPv4Address
|
||||
ipv6, # type: IPv6Network
|
||||
enabled, # type: bool
|
||||
ipv4: IPv4Address,
|
||||
ipv6: IPv6Network,
|
||||
enabled: bool,
|
||||
):
|
||||
self.ipv4 = ipv4
|
||||
self.ipv6 = ipv6
|
||||
|
@ -305,8 +420,8 @@ class IPv4Address(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ip, # type: str
|
||||
dns_ptr, # type: str
|
||||
ip: str,
|
||||
dns_ptr: str,
|
||||
):
|
||||
self.ip = ip
|
||||
self.dns_ptr = dns_ptr
|
||||
|
@ -323,8 +438,8 @@ class IPv6Network(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ip, # type: str
|
||||
dns_ptr, # type: str
|
||||
ip: str,
|
||||
dns_ptr: str,
|
||||
):
|
||||
self.ip = ip
|
||||
self.dns_ptr = dns_ptr
|
||||
|
@ -343,8 +458,8 @@ class PrivateNet(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
network, # type: BoundNetwork
|
||||
ip, # type: str
|
||||
network: BoundNetwork,
|
||||
ip: str,
|
||||
):
|
||||
self.network = network
|
||||
self.ip = ip
|
||||
|
@ -363,8 +478,8 @@ class CreateLoadBalancerResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
load_balancer, # type: BoundLoadBalancer
|
||||
action, # type: BoundAction
|
||||
load_balancer: BoundLoadBalancer,
|
||||
action: BoundAction,
|
||||
):
|
||||
self.load_balancer = load_balancer
|
||||
self.action = action
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundLocation, LocationsClient, LocationsPageResult # noqa: F401
|
||||
from .domain import Location # noqa: F401
|
|
@ -1,16 +1,29 @@
|
|||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import Location
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundLocation(BoundModelBase):
|
||||
_client: LocationsClient
|
||||
|
||||
model = Location
|
||||
|
||||
|
||||
class LocationsClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "locations"
|
||||
class LocationsPageResult(NamedTuple):
|
||||
locations: list[BoundLocation]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> locations.client.BoundLocation
|
||||
|
||||
class LocationsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundLocation:
|
||||
"""Get a specific location by its ID.
|
||||
|
||||
:param id: int
|
||||
|
@ -19,8 +32,12 @@ class LocationsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
response = self._client.request(url=f"/locations/{id}", method="GET")
|
||||
return BoundLocation(self, response["location"])
|
||||
|
||||
def get_list(self, name=None, page=None, per_page=None):
|
||||
# type: (Optional[str], Optional[int], Optional[int]) -> PageResult[List[BoundLocation], Meta]
|
||||
def get_list(
|
||||
self,
|
||||
name: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> LocationsPageResult:
|
||||
"""Get a list of locations
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -31,7 +48,7 @@ class LocationsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundLocation <hcloud.locations.client.BoundLocation>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if page is not None:
|
||||
|
@ -44,24 +61,22 @@ class LocationsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundLocation(self, location_data)
|
||||
for location_data in response["locations"]
|
||||
]
|
||||
return self._add_meta_to_result(locations, response)
|
||||
return LocationsPageResult(locations, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None):
|
||||
# type: (Optional[str]) -> List[BoundLocation]
|
||||
def get_all(self, name: str | None = None) -> list[BoundLocation]:
|
||||
"""Get all locations
|
||||
|
||||
:param name: str (optional)
|
||||
Can be used to filter locations by their name.
|
||||
:return: List[:class:`BoundLocation <hcloud.locations.client.BoundLocation>`]
|
||||
"""
|
||||
return super().get_all(name=name)
|
||||
return self._iter_pages(self.get_list, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundLocation
|
||||
def get_by_name(self, name: str) -> BoundLocation | None:
|
||||
"""Get location by name
|
||||
|
||||
:param name: str
|
||||
Used to get location by name.
|
||||
:return: :class:`BoundLocation <hcloud.locations.client.BoundLocation>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
|
||||
class Location(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -35,14 +37,14 @@ class Location(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
description=None,
|
||||
country=None,
|
||||
city=None,
|
||||
latitude=None,
|
||||
longitude=None,
|
||||
network_zone=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
country: str | None = None,
|
||||
city: str | None = None,
|
||||
latitude: float | None = None,
|
||||
longitude: float | None = None,
|
||||
network_zone: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundNetwork, NetworksClient, NetworksPageResult # noqa: F401
|
||||
from .domain import ( # noqa: F401
|
||||
CreateNetworkResponse,
|
||||
Network,
|
||||
NetworkRoute,
|
||||
NetworkSubnet,
|
||||
)
|
|
@ -1,13 +1,21 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import Network, NetworkRoute, NetworkSubnet
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundNetwork(BoundModelBase):
|
||||
_client: NetworksClient
|
||||
|
||||
model = Network
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
def __init__(self, client: NetworksClient, data: dict, complete: bool = True):
|
||||
subnets = data.get("subnets", [])
|
||||
if subnets is not None:
|
||||
subnets = [NetworkSubnet.from_dict(subnet) for subnet in subnets]
|
||||
|
@ -18,7 +26,7 @@ class BoundNetwork(BoundModelBase):
|
|||
routes = [NetworkRoute.from_dict(route) for route in routes]
|
||||
data["routes"] = routes
|
||||
|
||||
from ..servers.client import BoundServer
|
||||
from ..servers import BoundServer
|
||||
|
||||
servers = data.get("servers", [])
|
||||
if servers is not None:
|
||||
|
@ -32,10 +40,10 @@ class BoundNetwork(BoundModelBase):
|
|||
|
||||
def update(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
expose_routes_to_vswitch=None, # type: Optional[bool]
|
||||
labels=None, # type: Optional[Dict[str, str]]
|
||||
): # type: (...) -> BoundNetwork
|
||||
name: str | None = None,
|
||||
expose_routes_to_vswitch: bool | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundNetwork:
|
||||
"""Updates a network. You can update a network’s name and a networks’s labels.
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -54,16 +62,20 @@ class BoundNetwork(BoundModelBase):
|
|||
labels=labels,
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> BoundAction
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a network.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction, Meta]]
|
||||
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 action objects for a network.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -78,8 +90,11 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a network.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -90,8 +105,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def add_subnet(self, subnet):
|
||||
# type: (NetworkSubnet) -> List[BoundAction]
|
||||
def add_subnet(self, subnet: NetworkSubnet) -> BoundAction:
|
||||
"""Adds a subnet entry to a network.
|
||||
|
||||
:param subnet: :class:`NetworkSubnet <hcloud.networks.domain.NetworkSubnet>`
|
||||
|
@ -100,8 +114,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.add_subnet(self, subnet=subnet)
|
||||
|
||||
def delete_subnet(self, subnet):
|
||||
# type: (NetworkSubnet) -> List[BoundAction]
|
||||
def delete_subnet(self, subnet: NetworkSubnet) -> BoundAction:
|
||||
"""Removes a subnet entry from a network
|
||||
|
||||
:param subnet: :class:`NetworkSubnet <hcloud.networks.domain.NetworkSubnet>`
|
||||
|
@ -110,8 +123,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.delete_subnet(self, subnet=subnet)
|
||||
|
||||
def add_route(self, route):
|
||||
# type: (NetworkRoute) -> List[BoundAction]
|
||||
def add_route(self, route: NetworkRoute) -> BoundAction:
|
||||
"""Adds a route entry to a network.
|
||||
|
||||
:param route: :class:`NetworkRoute <hcloud.networks.domain.NetworkRoute>`
|
||||
|
@ -120,8 +132,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.add_route(self, route=route)
|
||||
|
||||
def delete_route(self, route):
|
||||
# type: (NetworkRoute) -> List[BoundAction]
|
||||
def delete_route(self, route: NetworkRoute) -> BoundAction:
|
||||
"""Removes a route entry to a network.
|
||||
|
||||
:param route: :class:`NetworkRoute <hcloud.networks.domain.NetworkRoute>`
|
||||
|
@ -130,8 +141,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.delete_route(self, route=route)
|
||||
|
||||
def change_ip_range(self, ip_range):
|
||||
# type: (str) -> List[BoundAction]
|
||||
def change_ip_range(self, ip_range: str) -> BoundAction:
|
||||
"""Changes the IP range of a network.
|
||||
|
||||
:param ip_range: str
|
||||
|
@ -140,8 +150,7 @@ class BoundNetwork(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_ip_range(self, ip_range=ip_range)
|
||||
|
||||
def change_protection(self, delete=None):
|
||||
# type: (Optional[bool]) -> BoundAction
|
||||
def change_protection(self, delete: bool | None = None) -> BoundAction:
|
||||
"""Changes the protection configuration of a network.
|
||||
|
||||
:param delete: boolean
|
||||
|
@ -151,11 +160,15 @@ class BoundNetwork(BoundModelBase):
|
|||
return self._client.change_protection(self, delete=delete)
|
||||
|
||||
|
||||
class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "networks"
|
||||
class NetworksPageResult(NamedTuple):
|
||||
networks: list[BoundNetwork]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundNetwork
|
||||
|
||||
class NetworksClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundNetwork:
|
||||
"""Get a specific network
|
||||
|
||||
:param id: int
|
||||
|
@ -166,12 +179,11 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundNetwork], Meta]
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> NetworksPageResult:
|
||||
"""Get a list of networks from this account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -184,7 +196,7 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if label_selector is not None:
|
||||
|
@ -196,13 +208,16 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
response = self._client.request(url="/networks", method="GET", params=params)
|
||||
|
||||
ass_networks = [
|
||||
networks = [
|
||||
BoundNetwork(self, network_data) for network_data in response["networks"]
|
||||
]
|
||||
return self._add_meta_to_result(ass_networks, response)
|
||||
return NetworksPageResult(networks, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None, label_selector=None):
|
||||
# type: (Optional[str], Optional[str]) -> List[BoundNetwork]
|
||||
def get_all(
|
||||
self,
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
) -> list[BoundNetwork]:
|
||||
"""Get all networks from this account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -211,27 +226,26 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter networks by labels. The response will only contain networks matching the label selector.
|
||||
:return: List[:class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`]
|
||||
"""
|
||||
return super().get_all(name=name, label_selector=label_selector)
|
||||
return self._iter_pages(self.get_list, name=name, label_selector=label_selector)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundNetwork
|
||||
def get_by_name(self, name: str) -> BoundNetwork | None:
|
||||
"""Get network by name
|
||||
|
||||
:param name: str
|
||||
Used to get network by name.
|
||||
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
name, # type: str
|
||||
ip_range, # type: str
|
||||
subnets=None, # type: Optional[List[NetworkSubnet]]
|
||||
routes=None, # type: Optional[List[NetworkRoute]]
|
||||
expose_routes_to_vswitch=None, # type: Optional[bool]
|
||||
labels=None, # type: Optional[Dict[str, str]]
|
||||
):
|
||||
name: str,
|
||||
ip_range: str,
|
||||
subnets: list[NetworkSubnet] | None = None,
|
||||
routes: list[NetworkRoute] | None = None,
|
||||
expose_routes_to_vswitch: bool | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundNetwork:
|
||||
"""Creates a network with range ip_range.
|
||||
|
||||
:param name: str
|
||||
|
@ -249,11 +263,11 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
|
||||
"""
|
||||
data = {"name": name, "ip_range": ip_range}
|
||||
data: dict[str, Any] = {"name": name, "ip_range": ip_range}
|
||||
if subnets is not None:
|
||||
data_subnets = []
|
||||
for subnet in subnets:
|
||||
data_subnet = {
|
||||
data_subnet: dict[str, Any] = {
|
||||
"type": subnet.type,
|
||||
"ip_range": subnet.ip_range,
|
||||
"network_zone": subnet.network_zone,
|
||||
|
@ -280,8 +294,13 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
return BoundNetwork(self, response["network"])
|
||||
|
||||
def update(self, network, name=None, expose_routes_to_vswitch=None, labels=None):
|
||||
# type:(Network, Optional[str], Optional[bool], Optional[Dict[str, str]]) -> BoundNetwork
|
||||
def update(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
name: str | None = None,
|
||||
expose_routes_to_vswitch: bool | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundNetwork:
|
||||
"""Updates a network. You can update a network’s name and a network’s labels.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -294,7 +313,7 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
data.update({"name": name})
|
||||
|
||||
|
@ -311,8 +330,7 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundNetwork(self, response["network"])
|
||||
|
||||
def delete(self, network):
|
||||
# type: (Network) -> BoundAction
|
||||
def delete(self, network: Network | BoundNetwork) -> bool:
|
||||
"""Deletes a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -322,9 +340,13 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
return True
|
||||
|
||||
def get_actions_list(
|
||||
self, network, status=None, sort=None, page=None, per_page=None
|
||||
):
|
||||
# type: (Network, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta]
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -338,7 +360,7 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -357,10 +379,14 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(self, network, status=None, sort=None):
|
||||
# type: (Network, Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -370,10 +396,18 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
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 <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(network, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
network,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def add_subnet(self, network, subnet):
|
||||
# type: (Union[Network, BoundNetwork], NetworkSubnet) -> List[BoundAction]
|
||||
def add_subnet(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
subnet: NetworkSubnet,
|
||||
) -> BoundAction:
|
||||
"""Adds a subnet entry to a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -381,23 +415,27 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The NetworkSubnet you want to add to the Network
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"type": subnet.type, "network_zone": subnet.network_zone}
|
||||
data: dict[str, Any] = {
|
||||
"type": subnet.type,
|
||||
"network_zone": subnet.network_zone,
|
||||
}
|
||||
if subnet.ip_range is not None:
|
||||
data["ip_range"] = subnet.ip_range
|
||||
if subnet.vswitch_id is not None:
|
||||
data["vswitch_id"] = subnet.vswitch_id
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/add_subnet".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/add_subnet",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def delete_subnet(self, network, subnet):
|
||||
# type: (Union[Network, BoundNetwork], NetworkSubnet) -> List[BoundAction]
|
||||
def delete_subnet(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
subnet: NetworkSubnet,
|
||||
) -> BoundAction:
|
||||
"""Removes a subnet entry from a network
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -405,19 +443,20 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The NetworkSubnet you want to remove from the Network
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"ip_range": subnet.ip_range}
|
||||
data: dict[str, Any] = {"ip_range": subnet.ip_range}
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/delete_subnet".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/delete_subnet",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def add_route(self, network, route):
|
||||
# type: (Union[Network, BoundNetwork], NetworkRoute) -> List[BoundAction]
|
||||
def add_route(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
route: NetworkRoute,
|
||||
) -> BoundAction:
|
||||
"""Adds a route entry to a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -425,19 +464,23 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The NetworkRoute you want to add to the Network
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"destination": route.destination, "gateway": route.gateway}
|
||||
data: dict[str, Any] = {
|
||||
"destination": route.destination,
|
||||
"gateway": route.gateway,
|
||||
}
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/add_route".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/add_route",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def delete_route(self, network, route):
|
||||
# type: (Union[Network, BoundNetwork], NetworkRoute) -> List[BoundAction]
|
||||
def delete_route(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
route: NetworkRoute,
|
||||
) -> BoundAction:
|
||||
"""Removes a route entry to a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -445,19 +488,23 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The NetworkRoute you want to remove from the Network
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"destination": route.destination, "gateway": route.gateway}
|
||||
data: dict[str, Any] = {
|
||||
"destination": route.destination,
|
||||
"gateway": route.gateway,
|
||||
}
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/delete_route".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/delete_route",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_ip_range(self, network, ip_range):
|
||||
# type: (Union[Network, BoundNetwork], str) -> List[BoundAction]
|
||||
def change_ip_range(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
ip_range: str,
|
||||
) -> BoundAction:
|
||||
"""Changes the IP range of a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -465,19 +512,20 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
The new prefix for the whole network.
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"ip_range": ip_range}
|
||||
data: dict[str, Any] = {"ip_range": ip_range}
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/change_ip_range".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/change_ip_range",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_protection(self, network, delete=None):
|
||||
# type: (Union[Network, BoundNetwork], Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
network: Network | BoundNetwork,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of a network.
|
||||
|
||||
:param network: :class:`BoundNetwork <hcloud.networks.client.BoundNetwork>` or :class:`Network <hcloud.networks.domain.Network>`
|
||||
|
@ -485,14 +533,12 @@ class NetworksClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If True, prevents the network from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/networks/{network_id}/actions/change_protection".format(
|
||||
network_id=network.id
|
||||
),
|
||||
url=f"/networks/{network.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..servers import BoundServer
|
||||
from .client import BoundNetwork
|
||||
|
||||
|
||||
class Network(BaseDomain):
|
||||
|
@ -44,16 +53,16 @@ class Network(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
name=None,
|
||||
created=None,
|
||||
ip_range=None,
|
||||
subnets=None,
|
||||
routes=None,
|
||||
expose_routes_to_vswitch=None,
|
||||
servers=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
id: int,
|
||||
name: str | None = None,
|
||||
created: str | None = None,
|
||||
ip_range: str | None = None,
|
||||
subnets: list[NetworkSubnet] | None = None,
|
||||
routes: list[NetworkRoute] | None = None,
|
||||
expose_routes_to_vswitch: bool | None = None,
|
||||
servers: list[BoundServer] | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -91,7 +100,12 @@ class NetworkSubnet(BaseDomain):
|
|||
__slots__ = ("type", "ip_range", "network_zone", "gateway", "vswitch_id")
|
||||
|
||||
def __init__(
|
||||
self, ip_range, type=None, network_zone=None, gateway=None, vswitch_id=None
|
||||
self,
|
||||
ip_range: str,
|
||||
type: str | None = None,
|
||||
network_zone: str | None = None,
|
||||
gateway: str | None = None,
|
||||
vswitch_id: int | None = None,
|
||||
):
|
||||
self.type = type
|
||||
self.ip_range = ip_range
|
||||
|
@ -111,7 +125,7 @@ class NetworkRoute(BaseDomain):
|
|||
|
||||
__slots__ = ("destination", "gateway")
|
||||
|
||||
def __init__(self, destination, gateway):
|
||||
def __init__(self, destination: str, gateway: str):
|
||||
self.destination = destination
|
||||
self.gateway = gateway
|
||||
|
||||
|
@ -129,8 +143,8 @@ class CreateNetworkResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
network, # type: BoundNetwork
|
||||
action, # type: BoundAction
|
||||
network: BoundNetwork,
|
||||
action: BoundAction,
|
||||
):
|
||||
self.network = network
|
||||
self.action = action
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundPlacementGroup,
|
||||
PlacementGroupsClient,
|
||||
PlacementGroupsPageResult,
|
||||
)
|
||||
from .domain import CreatePlacementGroupResponse, PlacementGroup # noqa: F401
|
|
@ -1,13 +1,25 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import CreatePlacementGroupResponse, PlacementGroup
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundPlacementGroup(BoundModelBase):
|
||||
_client: PlacementGroupsClient
|
||||
|
||||
model = PlacementGroup
|
||||
|
||||
def update(self, labels=None, name=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]], Optional[str]) -> BoundPlacementGroup
|
||||
def update(
|
||||
self,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundPlacementGroup:
|
||||
"""Updates the name or labels of a Placement Group
|
||||
|
||||
:param labels: Dict[str, str] (optional)
|
||||
|
@ -18,8 +30,7 @@ class BoundPlacementGroup(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, labels, name)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a Placement Group
|
||||
|
||||
:return: boolean
|
||||
|
@ -27,11 +38,15 @@ class BoundPlacementGroup(BoundModelBase):
|
|||
return self._client.delete(self)
|
||||
|
||||
|
||||
class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "placement_groups"
|
||||
class PlacementGroupsPageResult(NamedTuple):
|
||||
placement_groups: list[BoundPlacementGroup]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundPlacementGroup
|
||||
|
||||
class PlacementGroupsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundPlacementGroup:
|
||||
"""Returns a specific Placement Group object
|
||||
|
||||
:param id: int
|
||||
|
@ -45,14 +60,13 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
name=None, # type: Optional[str]
|
||||
sort=None, # type: Optional[List[str]]
|
||||
type=None, # type: Optional[str]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundPlacementGroup]]
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
name: str | None = None,
|
||||
sort: list[str] | None = None,
|
||||
type: str | None = None,
|
||||
) -> PlacementGroupsPageResult:
|
||||
"""Get a list of Placement Groups
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -68,7 +82,7 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: (List[:class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
|
||||
if label_selector is not None:
|
||||
params["label_selector"] = label_selector
|
||||
|
@ -90,10 +104,14 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for placement_group_data in response["placement_groups"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(placement_groups, response)
|
||||
return PlacementGroupsPageResult(placement_groups, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, label_selector=None, name=None, sort=None):
|
||||
# type: (Optional[str], Optional[str], Optional[List[str]]) -> List[BoundPlacementGroup]
|
||||
def get_all(
|
||||
self,
|
||||
label_selector: str | None = None,
|
||||
name: str | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundPlacementGroup]:
|
||||
"""Get all Placement Groups
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -104,25 +122,28 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default))
|
||||
:return: List[:class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`]
|
||||
"""
|
||||
return super().get_all(label_selector=label_selector, name=name, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
label_selector=label_selector,
|
||||
name=name,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundPlacementGroup
|
||||
def get_by_name(self, name: str) -> BoundPlacementGroup | None:
|
||||
"""Get Placement Group by name
|
||||
|
||||
:param name: str
|
||||
Used to get Placement Group by name
|
||||
:return: class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
name, # type: str
|
||||
type, # type: str
|
||||
labels=None, # type: Optional[Dict[str, str]]
|
||||
):
|
||||
# type: (...) -> CreatePlacementGroupResponse
|
||||
name: str,
|
||||
type: str,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> CreatePlacementGroupResponse:
|
||||
"""Creates a new Placement Group.
|
||||
|
||||
:param name: str
|
||||
|
@ -134,7 +155,7 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
:return: :class:`CreatePlacementGroupResponse <hcloud.placement_groups.domain.CreatePlacementGroupResponse>`
|
||||
"""
|
||||
data = {"name": name, "type": type}
|
||||
data: dict[str, Any] = {"name": name, "type": type}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
response = self._client.request(
|
||||
|
@ -143,7 +164,7 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
action = None
|
||||
if response.get("action") is not None:
|
||||
action = BoundAction(self._client.action, response["action"])
|
||||
action = BoundAction(self._client.actions, response["action"])
|
||||
|
||||
result = CreatePlacementGroupResponse(
|
||||
placement_group=BoundPlacementGroup(self, response["placement_group"]),
|
||||
|
@ -151,8 +172,12 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return result
|
||||
|
||||
def update(self, placement_group, labels=None, name=None):
|
||||
# type: (PlacementGroup, Optional[Dict[str, str]], Optional[str]) -> BoundPlacementGroup
|
||||
def update(
|
||||
self,
|
||||
placement_group: PlacementGroup | BoundPlacementGroup,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundPlacementGroup:
|
||||
"""Updates the description or labels of a Placement Group.
|
||||
|
||||
:param placement_group: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>` or :class:`PlacementGroup <hcloud.placement_groups.domain.PlacementGroup>`
|
||||
|
@ -163,32 +188,27 @@ class PlacementGroupsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>`
|
||||
"""
|
||||
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
if name is not None:
|
||||
data["name"] = name
|
||||
|
||||
response = self._client.request(
|
||||
url="/placement_groups/{placement_group_id}".format(
|
||||
placement_group_id=placement_group.id
|
||||
),
|
||||
url=f"/placement_groups/{placement_group.id}",
|
||||
method="PUT",
|
||||
json=data,
|
||||
)
|
||||
return BoundPlacementGroup(self, response["placement_group"])
|
||||
|
||||
def delete(self, placement_group):
|
||||
# type: (PlacementGroup) -> bool
|
||||
def delete(self, placement_group: PlacementGroup | BoundPlacementGroup) -> bool:
|
||||
"""Deletes a Placement Group.
|
||||
|
||||
:param placement_group: :class:`BoundPlacementGroup <hcloud.placement_groups.client.BoundPlacementGroup>` or :class:`PlacementGroup <hcloud.placement_groups.domain.PlacementGroup>`
|
||||
:return: boolean
|
||||
"""
|
||||
self._client.request(
|
||||
url="/placement_groups/{placement_group_id}".format(
|
||||
placement_group_id=placement_group.id
|
||||
),
|
||||
url=f"/placement_groups/{placement_group.id}",
|
||||
method="DELETE",
|
||||
)
|
||||
return True
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from .client import BoundPlacementGroup
|
||||
|
||||
|
||||
class PlacementGroup(BaseDomain):
|
||||
|
@ -31,7 +39,13 @@ class PlacementGroup(BaseDomain):
|
|||
TYPE_SPREAD = "spread"
|
||||
|
||||
def __init__(
|
||||
self, id=None, name=None, labels=None, servers=None, type=None, created=None
|
||||
self,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
servers: list[int] | None = None,
|
||||
type: str | None = None,
|
||||
created: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -54,8 +68,8 @@ class CreatePlacementGroupResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
placement_group, # type: BoundPlacementGroup
|
||||
action, # type: BoundAction
|
||||
placement_group: BoundPlacementGroup,
|
||||
action: BoundAction | None,
|
||||
):
|
||||
self.placement_group = placement_group
|
||||
self.action = action
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundPrimaryIP, PrimaryIPsClient, PrimaryIPsPageResult # noqa: F401
|
||||
from .domain import CreatePrimaryIPResponse, PrimaryIP # noqa: F401
|
|
@ -1,13 +1,23 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import CreatePrimaryIPResponse, PrimaryIP
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
from ..datacenters import BoundDatacenter, Datacenter
|
||||
|
||||
|
||||
class BoundPrimaryIP(BoundModelBase):
|
||||
_client: PrimaryIPsClient
|
||||
|
||||
model = PrimaryIP
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
from ..datacenters.client import BoundDatacenter
|
||||
def __init__(self, client: PrimaryIPsClient, data: dict, complete: bool = True):
|
||||
from ..datacenters import BoundDatacenter
|
||||
|
||||
datacenter = data.get("datacenter", {})
|
||||
if datacenter:
|
||||
|
@ -15,8 +25,12 @@ class BoundPrimaryIP(BoundModelBase):
|
|||
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def update(self, auto_delete=None, labels=None, name=None):
|
||||
# type: (Optional[bool], Optional[Dict[str, str]], Optional[str]) -> BoundPrimaryIP
|
||||
def update(
|
||||
self,
|
||||
auto_delete: bool | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundPrimaryIP:
|
||||
"""Updates the description or labels of a Primary IP.
|
||||
|
||||
:param auto_delete: bool (optional)
|
||||
|
@ -31,16 +45,14 @@ class BoundPrimaryIP(BoundModelBase):
|
|||
self, auto_delete=auto_delete, labels=labels, name=name
|
||||
)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes a Primary IP. If it is currently assigned to a server it will automatically get unassigned.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def change_protection(self, delete=None):
|
||||
# type: (Optional[bool]) -> BoundAction
|
||||
def change_protection(self, delete: bool | None = None) -> BoundAction:
|
||||
"""Changes the protection configuration of the Primary IP.
|
||||
|
||||
:param delete: boolean
|
||||
|
@ -49,8 +61,7 @@ class BoundPrimaryIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.change_protection(self, delete)
|
||||
|
||||
def assign(self, assignee_id, assignee_type):
|
||||
# type: (int,str) -> BoundAction
|
||||
def assign(self, assignee_id: int, assignee_type: str) -> BoundAction:
|
||||
"""Assigns a Primary IP to a assignee.
|
||||
|
||||
:param assignee_id: int`
|
||||
|
@ -61,16 +72,14 @@ class BoundPrimaryIP(BoundModelBase):
|
|||
"""
|
||||
return self._client.assign(self, assignee_id, assignee_type)
|
||||
|
||||
def unassign(self):
|
||||
# type: () -> BoundAction
|
||||
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.
|
||||
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
return self._client.unassign(self)
|
||||
|
||||
def change_dns_ptr(self, ip, dns_ptr):
|
||||
# type: (str, str) -> BoundAction
|
||||
def change_dns_ptr(self, ip: str, dns_ptr: str) -> BoundAction:
|
||||
"""Changes the hostname that will appear when getting the hostname belonging to this Primary IP.
|
||||
|
||||
:param ip: str
|
||||
|
@ -82,11 +91,15 @@ class BoundPrimaryIP(BoundModelBase):
|
|||
return self._client.change_dns_ptr(self, ip, dns_ptr)
|
||||
|
||||
|
||||
class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "primary_ips"
|
||||
class PrimaryIPsPageResult(NamedTuple):
|
||||
primary_ips: list[BoundPrimaryIP]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundPrimaryIP
|
||||
|
||||
class PrimaryIPsClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundPrimaryIP:
|
||||
"""Returns a specific Primary IP object.
|
||||
|
||||
:param id: int
|
||||
|
@ -97,13 +110,12 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
name=None, # type: Optional[str]
|
||||
ip=None, # type: Optional[ip]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundPrimaryIP]]
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
name: str | None = None,
|
||||
ip: str | None = None,
|
||||
) -> PrimaryIPsPageResult:
|
||||
"""Get a list of primary ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -118,7 +130,7 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter resources by their ip. The response will only contain the resources matching the specified ip.
|
||||
:return: (List[:class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
|
||||
if label_selector is not None:
|
||||
params["label_selector"] = label_selector
|
||||
|
@ -137,10 +149,13 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
for primary_ip_data in response["primary_ips"]
|
||||
]
|
||||
|
||||
return self._add_meta_to_result(primary_ips, response)
|
||||
return PrimaryIPsPageResult(primary_ips, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, label_selector=None, name=None):
|
||||
# type: (Optional[str], Optional[str]) -> List[BoundPrimaryIP]
|
||||
def get_all(
|
||||
self,
|
||||
label_selector: str | None = None,
|
||||
name: str | None = None,
|
||||
) -> list[BoundPrimaryIP]:
|
||||
"""Get all primary ips from this account
|
||||
|
||||
:param label_selector: str (optional)
|
||||
|
@ -149,29 +164,28 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter networks by their name.
|
||||
:return: List[:class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>`]
|
||||
"""
|
||||
return super().get_all(label_selector=label_selector, name=name)
|
||||
return self._iter_pages(self.get_list, label_selector=label_selector, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundPrimaryIP
|
||||
def get_by_name(self, name: str) -> BoundPrimaryIP | None:
|
||||
"""Get Primary IP by name
|
||||
|
||||
:param name: str
|
||||
Used to get Primary IP by name.
|
||||
:return: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
type, # type: str
|
||||
datacenter, # type: Datacenter
|
||||
name, # type: str
|
||||
assignee_type="server", # type: Optional[str]
|
||||
assignee_id=None, # type: Optional[int]
|
||||
auto_delete=False, # type: Optional[bool]
|
||||
labels=None, # type: Optional[dict]
|
||||
):
|
||||
# type: (...) -> CreatePrimaryIPResponse
|
||||
type: str,
|
||||
# TODO: Make the datacenter argument optional
|
||||
datacenter: Datacenter | BoundDatacenter | None,
|
||||
name: str,
|
||||
assignee_type: str | None = "server",
|
||||
assignee_id: int | None = None,
|
||||
auto_delete: bool | None = False,
|
||||
labels: dict | None = None,
|
||||
) -> CreatePrimaryIPResponse:
|
||||
"""Creates a new Primary IP assigned to a server.
|
||||
|
||||
:param type: str
|
||||
|
@ -186,14 +200,15 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`CreatePrimaryIPResponse <hcloud.primary_ips.domain.CreatePrimaryIPResponse>`
|
||||
"""
|
||||
|
||||
data = {
|
||||
data: dict[str, Any] = {
|
||||
"type": type,
|
||||
"assignee_type": assignee_type,
|
||||
"auto_delete": auto_delete,
|
||||
"datacenter": datacenter.id_or_name,
|
||||
"name": name,
|
||||
}
|
||||
if assignee_id:
|
||||
if datacenter is not None:
|
||||
data["datacenter"] = datacenter.id_or_name
|
||||
if assignee_id is not None:
|
||||
data["assignee_id"] = assignee_id
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
|
@ -209,8 +224,13 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return result
|
||||
|
||||
def update(self, primary_ip, auto_delete=None, labels=None, name=None):
|
||||
# type: (PrimaryIP, Optional[bool], Optional[Dict[str, str]], Optional[str]) -> BoundPrimaryIP
|
||||
def update(
|
||||
self,
|
||||
primary_ip: PrimaryIP | BoundPrimaryIP,
|
||||
auto_delete: bool | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
name: str | None = None,
|
||||
) -> BoundPrimaryIP:
|
||||
"""Updates the name, auto_delete or labels of a Primary IP.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
|
@ -222,7 +242,7 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
New name to set
|
||||
:return: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if auto_delete is not None:
|
||||
data["auto_delete"] = auto_delete
|
||||
if labels is not None:
|
||||
|
@ -237,8 +257,7 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundPrimaryIP(self, response["primary_ip"])
|
||||
|
||||
def delete(self, primary_ip):
|
||||
# type: (PrimaryIP) -> bool
|
||||
def delete(self, primary_ip: PrimaryIP | BoundPrimaryIP) -> bool:
|
||||
"""Deletes a Primary IP. If it is currently assigned to an assignee it will automatically get unassigned.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
|
@ -251,8 +270,11 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
# Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised
|
||||
return True
|
||||
|
||||
def change_protection(self, primary_ip, delete=None):
|
||||
# type: (PrimaryIP, Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
primary_ip: PrimaryIP | BoundPrimaryIP,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of the Primary IP.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
|
@ -260,21 +282,23 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If true, prevents the Primary IP from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/primary_ips/{primary_ip_id}/actions/change_protection".format(
|
||||
primary_ip_id=primary_ip.id
|
||||
),
|
||||
url=f"/primary_ips/{primary_ip.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def assign(self, primary_ip, assignee_id, assignee_type="server"):
|
||||
# type: (PrimaryIP, int, str) -> BoundAction
|
||||
def assign(
|
||||
self,
|
||||
primary_ip: PrimaryIP | BoundPrimaryIP,
|
||||
assignee_id: int,
|
||||
assignee_type: str = "server",
|
||||
) -> BoundAction:
|
||||
"""Assigns a Primary IP to a assignee_id.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
|
@ -285,31 +309,30 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/primary_ips/{primary_ip_id}/actions/assign".format(
|
||||
primary_ip_id=primary_ip.id
|
||||
),
|
||||
url=f"/primary_ips/{primary_ip.id}/actions/assign",
|
||||
method="POST",
|
||||
json={"assignee_id": assignee_id, "assignee_type": assignee_type},
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def unassign(self, primary_ip):
|
||||
# type: (PrimaryIP) -> BoundAction
|
||||
def unassign(self, primary_ip: PrimaryIP | BoundPrimaryIP) -> BoundAction:
|
||||
"""Unassigns a Primary IP, resulting in it being unreachable. You may assign it to a server again at a later time.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/primary_ips/{primary_ip_id}/actions/unassign".format(
|
||||
primary_ip_id=primary_ip.id
|
||||
),
|
||||
url=f"/primary_ips/{primary_ip.id}/actions/unassign",
|
||||
method="POST",
|
||||
)
|
||||
return BoundAction(self._client.actions, response["action"])
|
||||
|
||||
def change_dns_ptr(self, primary_ip, ip, dns_ptr):
|
||||
# type: (PrimaryIP, str, str) -> BoundAction
|
||||
def change_dns_ptr(
|
||||
self,
|
||||
primary_ip: PrimaryIP | BoundPrimaryIP,
|
||||
ip: str,
|
||||
dns_ptr: str,
|
||||
) -> BoundAction:
|
||||
"""Changes the dns ptr that will appear when getting the dns ptr belonging to this Primary IP.
|
||||
|
||||
:param primary_ip: :class:`BoundPrimaryIP <hcloud.primary_ips.client.BoundPrimaryIP>` or :class:`PrimaryIP <hcloud.primary_ips.domain.PrimaryIP>`
|
||||
|
@ -320,9 +343,7 @@ class PrimaryIPsClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
response = self._client.request(
|
||||
url="/primary_ips/{primary_ip_id}/actions/change_dns_ptr".format(
|
||||
primary_ip_id=primary_ip.id
|
||||
),
|
||||
url=f"/primary_ips/{primary_ip.id}/actions/change_dns_ptr",
|
||||
method="POST",
|
||||
json={"ip": ip, "dns_ptr": dns_ptr},
|
||||
)
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..datacenters import BoundDatacenter
|
||||
from .client import BoundPrimaryIP
|
||||
|
||||
|
||||
class PrimaryIP(BaseDomain):
|
||||
|
@ -55,19 +64,19 @@ class PrimaryIP(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
type=None,
|
||||
ip=None,
|
||||
dns_ptr=None,
|
||||
datacenter=None,
|
||||
blocked=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
created=None,
|
||||
name=None,
|
||||
assignee_id=None,
|
||||
assignee_type=None,
|
||||
auto_delete=None,
|
||||
id: int | None = None,
|
||||
type: str | None = None,
|
||||
ip: str | None = None,
|
||||
dns_ptr: list[dict] | None = None,
|
||||
datacenter: BoundDatacenter | None = None,
|
||||
blocked: bool | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, dict] | None = None,
|
||||
created: str | None = None,
|
||||
name: str | None = None,
|
||||
assignee_id: int | None = None,
|
||||
assignee_type: str | None = None,
|
||||
auto_delete: bool | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.type = type
|
||||
|
@ -97,8 +106,8 @@ class CreatePrimaryIPResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
primary_ip, # type: BoundPrimaryIP
|
||||
action, # type: BoundAction
|
||||
primary_ip: BoundPrimaryIP,
|
||||
action: BoundAction | None,
|
||||
):
|
||||
self.primary_ip = primary_ip
|
||||
self.action = action
|
||||
|
|
1
plugins/module_utils/vendor/hcloud/py.typed
vendored
Normal file
1
plugins/module_utils/vendor/hcloud/py.typed
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
# Marker file for PEP 561.
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import ( # noqa: F401
|
||||
BoundServerType,
|
||||
ServerTypesClient,
|
||||
ServerTypesPageResult,
|
||||
)
|
||||
from .domain import ServerType # noqa: F401
|
|
@ -1,16 +1,29 @@
|
|||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import ServerType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundServerType(BoundModelBase):
|
||||
_client: ServerTypesClient
|
||||
|
||||
model = ServerType
|
||||
|
||||
|
||||
class ServerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "server_types"
|
||||
class ServerTypesPageResult(NamedTuple):
|
||||
server_types: list[BoundServerType]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundServerType
|
||||
|
||||
class ServerTypesClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundServerType:
|
||||
"""Returns a specific Server Type.
|
||||
|
||||
:param id: int
|
||||
|
@ -19,8 +32,12 @@ class ServerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
response = self._client.request(url=f"/server_types/{id}", method="GET")
|
||||
return BoundServerType(self, response["server_type"])
|
||||
|
||||
def get_list(self, name=None, page=None, per_page=None):
|
||||
# type: (Optional[str], Optional[int], Optional[int]) -> PageResults[List[BoundServerType], Meta]
|
||||
def get_list(
|
||||
self,
|
||||
name: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ServerTypesPageResult:
|
||||
"""Get a list of Server types
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -31,7 +48,7 @@ class ServerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundServerType <hcloud.server_types.client.BoundServerType>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if page is not None:
|
||||
|
@ -46,24 +63,22 @@ class ServerTypesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundServerType(self, server_type_data)
|
||||
for server_type_data in response["server_types"]
|
||||
]
|
||||
return self._add_meta_to_result(server_types, response)
|
||||
return ServerTypesPageResult(server_types, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None):
|
||||
# type: (Optional[str]) -> List[BoundServerType]
|
||||
def get_all(self, name: str | None = None) -> list[BoundServerType]:
|
||||
"""Get all Server types
|
||||
|
||||
:param name: str (optional)
|
||||
Can be used to filter server type by their name.
|
||||
:return: List[:class:`BoundServerType <hcloud.server_types.client.BoundServerType>`]
|
||||
"""
|
||||
return super().get_all(name=name)
|
||||
return self._iter_pages(self.get_list, name=name)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundServerType
|
||||
def get_by_name(self, name: str) -> BoundServerType | None:
|
||||
"""Get Server type by name
|
||||
|
||||
:param name: str
|
||||
Used to get Server type by name.
|
||||
:return: :class:`BoundServerType <hcloud.server_types.client.BoundServerType>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..deprecation.domain import DeprecationInfo
|
||||
from __future__ import annotations
|
||||
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
from ..deprecation import DeprecationInfo
|
||||
|
||||
|
||||
class ServerType(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -52,19 +54,19 @@ class ServerType(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
description=None,
|
||||
cores=None,
|
||||
memory=None,
|
||||
disk=None,
|
||||
prices=None,
|
||||
storage_type=None,
|
||||
cpu_type=None,
|
||||
architecture=None,
|
||||
deprecated=None,
|
||||
deprecation=None,
|
||||
included_traffic=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
cores: int | None = None,
|
||||
memory: int | None = None,
|
||||
disk: int | None = None,
|
||||
prices: dict | None = None,
|
||||
storage_type: str | None = None,
|
||||
cpu_type: str | None = None,
|
||||
architecture: str | None = None,
|
||||
deprecated: bool | None = None,
|
||||
deprecation: dict | None = None,
|
||||
included_traffic: int | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundServer, ServersClient, ServersPageResult # noqa: F401
|
||||
from .domain import ( # noqa: F401
|
||||
CreateServerResponse,
|
||||
EnableRescueResponse,
|
||||
IPv4Address,
|
||||
IPv6Network,
|
||||
PrivateNet,
|
||||
PublicNetwork,
|
||||
PublicNetworkFirewall,
|
||||
RequestConsoleResponse,
|
||||
ResetPasswordResponse,
|
||||
Server,
|
||||
ServerCreatePublicNetwork,
|
||||
)
|
506
plugins/module_utils/vendor/hcloud/servers/client.py
vendored
506
plugins/module_utils/vendor/hcloud/servers/client.py
vendored
File diff suppressed because it is too large
Load diff
128
plugins/module_utils/vendor/hcloud/servers/domain.py
vendored
128
plugins/module_utils/vendor/hcloud/servers/domain.py
vendored
|
@ -1,9 +1,27 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain
|
||||
from ..core import BaseDomain
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..datacenters import BoundDatacenter
|
||||
from ..firewalls import BoundFirewall
|
||||
from ..floating_ips import BoundFloatingIP
|
||||
from ..images import BoundImage
|
||||
from ..isos import BoundIso
|
||||
from ..networks import BoundNetwork
|
||||
from ..placement_groups import BoundPlacementGroup
|
||||
from ..primary_ips import BoundPrimaryIP, PrimaryIP
|
||||
from ..server_types import BoundServerType
|
||||
from ..volumes import BoundVolume
|
||||
from .client import BoundServer
|
||||
|
||||
|
||||
class Server(BaseDomain):
|
||||
|
@ -91,27 +109,27 @@ class Server(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
name=None,
|
||||
status=None,
|
||||
created=None,
|
||||
public_net=None,
|
||||
server_type=None,
|
||||
datacenter=None,
|
||||
image=None,
|
||||
iso=None,
|
||||
rescue_enabled=None,
|
||||
locked=None,
|
||||
backup_window=None,
|
||||
outgoing_traffic=None,
|
||||
ingoing_traffic=None,
|
||||
included_traffic=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
volumes=None,
|
||||
private_net=None,
|
||||
primary_disk_size=None,
|
||||
placement_group=None,
|
||||
id: int,
|
||||
name: str | None = None,
|
||||
status: str | None = None,
|
||||
created: str | None = None,
|
||||
public_net: PublicNetwork | None = None,
|
||||
server_type: BoundServerType | None = None,
|
||||
datacenter: BoundDatacenter | None = None,
|
||||
image: BoundImage | None = None,
|
||||
iso: BoundIso | None = None,
|
||||
rescue_enabled: bool | None = None,
|
||||
locked: bool | None = None,
|
||||
backup_window: str | None = None,
|
||||
outgoing_traffic: int | None = None,
|
||||
ingoing_traffic: int | None = None,
|
||||
included_traffic: int | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
volumes: list[BoundVolume] | None = None,
|
||||
private_net: list[PrivateNet] | None = None,
|
||||
primary_disk_size: int | None = None,
|
||||
placement_group: BoundPlacementGroup | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -153,10 +171,10 @@ class CreateServerResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
server, # type: BoundServer
|
||||
action, # type: BoundAction
|
||||
next_actions, # type: List[Action]
|
||||
root_password, # type: str
|
||||
server: BoundServer,
|
||||
action: BoundAction,
|
||||
next_actions: list[BoundAction],
|
||||
root_password: str | None,
|
||||
):
|
||||
self.server = server
|
||||
self.action = action
|
||||
|
@ -177,8 +195,8 @@ class ResetPasswordResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
action, # type: BoundAction
|
||||
root_password, # type: str
|
||||
action: BoundAction,
|
||||
root_password: str,
|
||||
):
|
||||
self.action = action
|
||||
self.root_password = root_password
|
||||
|
@ -197,8 +215,8 @@ class EnableRescueResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
action, # type: BoundAction
|
||||
root_password, # type: str
|
||||
action: BoundAction,
|
||||
root_password: str,
|
||||
):
|
||||
self.action = action
|
||||
self.root_password = root_password
|
||||
|
@ -219,9 +237,9 @@ class RequestConsoleResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
action, # type: BoundAction
|
||||
wss_url, # type: str
|
||||
password, # type: str
|
||||
action: BoundAction,
|
||||
wss_url: str,
|
||||
password: str,
|
||||
):
|
||||
self.action = action
|
||||
self.wss_url = wss_url
|
||||
|
@ -250,12 +268,12 @@ class PublicNetwork(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ipv4, # type: IPv4Address
|
||||
ipv6, # type: IPv6Network
|
||||
floating_ips, # type: List[BoundFloatingIP]
|
||||
primary_ipv4, # type: BoundPrimaryIP
|
||||
primary_ipv6, # type: BoundPrimaryIP
|
||||
firewalls=None, # type: List[PublicNetworkFirewall]
|
||||
ipv4: IPv4Address,
|
||||
ipv6: IPv6Network,
|
||||
floating_ips: list[BoundFloatingIP],
|
||||
primary_ipv4: BoundPrimaryIP | None,
|
||||
primary_ipv6: BoundPrimaryIP | None,
|
||||
firewalls: list[PublicNetworkFirewall] | None = None,
|
||||
):
|
||||
self.ipv4 = ipv4
|
||||
self.ipv6 = ipv6
|
||||
|
@ -281,8 +299,8 @@ class PublicNetworkFirewall(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
firewall, # type: BoundFirewall
|
||||
status, # type: str
|
||||
firewall: BoundFirewall,
|
||||
status: str,
|
||||
):
|
||||
self.firewall = firewall
|
||||
self.status = status
|
||||
|
@ -303,9 +321,9 @@ class IPv4Address(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ip, # type: str
|
||||
blocked, # type: bool
|
||||
dns_ptr, # type: str
|
||||
ip: str,
|
||||
blocked: bool,
|
||||
dns_ptr: str,
|
||||
):
|
||||
self.ip = ip
|
||||
self.blocked = blocked
|
||||
|
@ -331,9 +349,9 @@ class IPv6Network(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ip, # type: str
|
||||
blocked, # type: bool
|
||||
dns_ptr, # type: list
|
||||
ip: str,
|
||||
blocked: bool,
|
||||
dns_ptr: list,
|
||||
):
|
||||
self.ip = ip
|
||||
self.blocked = blocked
|
||||
|
@ -360,10 +378,10 @@ class PrivateNet(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
network, # type: BoundNetwork
|
||||
ip, # type: str
|
||||
alias_ips, # type: List[str]
|
||||
mac_address, # type: str
|
||||
network: BoundNetwork,
|
||||
ip: str,
|
||||
alias_ips: list[str],
|
||||
mac_address: str,
|
||||
):
|
||||
self.network = network
|
||||
self.ip = ip
|
||||
|
@ -384,10 +402,10 @@ class ServerCreatePublicNetwork(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
ipv4=None, # type: hcloud.primary_ips.domain.PrimaryIP
|
||||
ipv6=None, # type: hcloud.primary_ips.domain.PrimaryIP
|
||||
enable_ipv4=True, # type: bool
|
||||
enable_ipv6=True, # type: bool
|
||||
ipv4: PrimaryIP | None = None,
|
||||
ipv6: PrimaryIP | None = None,
|
||||
enable_ipv4: bool = True,
|
||||
enable_ipv6: bool = True,
|
||||
):
|
||||
self.ipv4 = ipv4
|
||||
self.ipv6 = ipv6
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundSSHKey, SSHKeysClient, SSHKeysPageResult # noqa: F401
|
||||
from .domain import SSHKey # noqa: F401
|
|
@ -1,12 +1,24 @@
|
|||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from .domain import SSHKey
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
|
||||
|
||||
class BoundSSHKey(BoundModelBase):
|
||||
_client: SSHKeysClient
|
||||
|
||||
model = SSHKey
|
||||
|
||||
def update(self, name=None, labels=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]]) -> BoundSSHKey
|
||||
def update(
|
||||
self,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundSSHKey:
|
||||
"""Updates an SSH key. You can update an SSH key name and an SSH key labels.
|
||||
|
||||
:param description: str (optional)
|
||||
|
@ -17,19 +29,22 @@ class BoundSSHKey(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, name, labels)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> bool
|
||||
def delete(self) -> bool:
|
||||
"""Deletes an SSH key. It cannot be used anymore.
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
|
||||
class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "ssh_keys"
|
||||
class SSHKeysPageResult(NamedTuple):
|
||||
ssh_keys: list[BoundSSHKey]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> BoundSSHKey
|
||||
|
||||
class SSHKeysClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundSSHKey:
|
||||
"""Get a specific SSH Key by its ID
|
||||
|
||||
:param id: int
|
||||
|
@ -40,13 +55,12 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
def get_list(
|
||||
self,
|
||||
name=None, # type: Optional[str]
|
||||
fingerprint=None, # type: Optional[str]
|
||||
label_selector=None, # type: Optional[str]
|
||||
page=None, # type: Optional[int]
|
||||
per_page=None, # type: Optional[int]
|
||||
):
|
||||
# type: (...) -> PageResults[List[BoundSSHKey], Meta]
|
||||
name: str | None = None,
|
||||
fingerprint: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> SSHKeysPageResult:
|
||||
"""Get a list of SSH keys from the account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -61,7 +75,7 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if fingerprint is not None:
|
||||
|
@ -75,13 +89,17 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
|
||||
response = self._client.request(url="/ssh_keys", method="GET", params=params)
|
||||
|
||||
ass_ssh_keys = [
|
||||
ssh_keys = [
|
||||
BoundSSHKey(self, server_data) for server_data in response["ssh_keys"]
|
||||
]
|
||||
return self._add_meta_to_result(ass_ssh_keys, response)
|
||||
return SSHKeysPageResult(ssh_keys, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, name=None, fingerprint=None, label_selector=None):
|
||||
# type: (Optional[str], Optional[str], Optional[str]) -> List[BoundSSHKey]
|
||||
def get_all(
|
||||
self,
|
||||
name: str | None = None,
|
||||
fingerprint: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
) -> list[BoundSSHKey]:
|
||||
"""Get all SSH keys from the account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -92,34 +110,37 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter SSH keys by labels. The response will only contain SSH keys matching the label selector.
|
||||
:return: List[:class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`]
|
||||
"""
|
||||
return super().get_all(
|
||||
name=name, fingerprint=fingerprint, label_selector=label_selector
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
name=name,
|
||||
fingerprint=fingerprint,
|
||||
label_selector=label_selector,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> SSHKeysClient
|
||||
def get_by_name(self, name: str) -> BoundSSHKey | None:
|
||||
"""Get ssh key by name
|
||||
|
||||
:param name: str
|
||||
Used to get ssh key by name.
|
||||
:return: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def get_by_fingerprint(self, fingerprint):
|
||||
# type: (str) -> BoundSSHKey
|
||||
def get_by_fingerprint(self, fingerprint: str) -> BoundSSHKey | None:
|
||||
"""Get ssh key by fingerprint
|
||||
|
||||
:param fingerprint: str
|
||||
Used to get ssh key by fingerprint.
|
||||
:return: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`
|
||||
"""
|
||||
response = self.get_list(fingerprint=fingerprint)
|
||||
sshkeys = response.ssh_keys
|
||||
return sshkeys[0] if sshkeys else None
|
||||
return self._get_first_by(fingerprint=fingerprint)
|
||||
|
||||
def create(self, name, public_key, labels=None):
|
||||
# type: (str, str, Optional[Dict[str, str]]) -> BoundSSHKey
|
||||
def create(
|
||||
self,
|
||||
name: str,
|
||||
public_key: str,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundSSHKey:
|
||||
"""Creates a new SSH key with the given name and public_key.
|
||||
|
||||
:param name: str
|
||||
|
@ -129,14 +150,18 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`
|
||||
"""
|
||||
data = {"name": name, "public_key": public_key}
|
||||
data: dict[str, Any] = {"name": name, "public_key": public_key}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
response = self._client.request(url="/ssh_keys", method="POST", json=data)
|
||||
return BoundSSHKey(self, response["ssh_key"])
|
||||
|
||||
def update(self, ssh_key, name=None, labels=None):
|
||||
# type: (SSHKey, Optional[str], Optional[Dict[str, str]]) -> BoundSSHKey
|
||||
def update(
|
||||
self,
|
||||
ssh_key: SSHKey | BoundSSHKey,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundSSHKey:
|
||||
"""Updates an SSH key. You can update an SSH key name and an SSH key labels.
|
||||
|
||||
:param ssh_key: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>` or :class:`SSHKey <hcloud.ssh_keys.domain.SSHKey>`
|
||||
|
@ -146,7 +171,7 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
data["name"] = name
|
||||
if labels is not None:
|
||||
|
@ -158,13 +183,12 @@ class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundSSHKey(self, response["ssh_key"])
|
||||
|
||||
def delete(self, ssh_key):
|
||||
# type: (SSHKey) -> bool
|
||||
self._client.request(url=f"/ssh_keys/{ssh_key.id}", method="DELETE")
|
||||
def delete(self, ssh_key: SSHKey | BoundSSHKey) -> bool:
|
||||
"""Deletes an SSH key. It cannot be used anymore.
|
||||
|
||||
:param ssh_key: :class:`BoundSSHKey <hcloud.ssh_keys.client.BoundSSHKey>` or :class:`SSHKey <hcloud.ssh_keys.domain.SSHKey>`
|
||||
:return: True
|
||||
"""
|
||||
self._client.request(url=f"/ssh_keys/{ssh_key.id}", method="DELETE")
|
||||
# Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised
|
||||
return True
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
|
||||
class SSHKey(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -27,12 +29,12 @@ class SSHKey(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
name=None,
|
||||
fingerprint=None,
|
||||
public_key=None,
|
||||
labels=None,
|
||||
created=None,
|
||||
id: int | None = None,
|
||||
name: str | None = None,
|
||||
fingerprint: str | None = None,
|
||||
public_key: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
created: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .client import BoundVolume, VolumesClient, VolumesPageResult # noqa: F401
|
||||
from .domain import CreateVolumeResponse, Volume # noqa: F401
|
198
plugins/module_utils/vendor/hcloud/volumes/client.py
vendored
198
plugins/module_utils/vendor/hcloud/volumes/client.py
vendored
|
@ -1,19 +1,29 @@
|
|||
from ..actions.client import BoundAction
|
||||
from ..core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin
|
||||
from ..core.domain import add_meta_to_result
|
||||
from ..locations.client import BoundLocation
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from ..actions import ActionsPageResult, BoundAction
|
||||
from ..core import BoundModelBase, ClientEntityBase, Meta
|
||||
from ..locations import BoundLocation
|
||||
from .domain import CreateVolumeResponse, Volume
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .._client import Client
|
||||
from ..locations import Location
|
||||
from ..servers import BoundServer, Server
|
||||
|
||||
|
||||
class BoundVolume(BoundModelBase):
|
||||
_client: VolumesClient
|
||||
|
||||
model = Volume
|
||||
|
||||
def __init__(self, client, data, complete=True):
|
||||
def __init__(self, client: VolumesClient, data: dict, complete: bool = True):
|
||||
location = data.get("location")
|
||||
if location is not None:
|
||||
data["location"] = BoundLocation(client._client.locations, location)
|
||||
|
||||
from ..servers.client import BoundServer
|
||||
from ..servers import BoundServer
|
||||
|
||||
server = data.get("server")
|
||||
if server is not None:
|
||||
|
@ -22,8 +32,13 @@ class BoundVolume(BoundModelBase):
|
|||
)
|
||||
super().__init__(client, data, complete)
|
||||
|
||||
def get_actions_list(self, status=None, sort=None, page=None, per_page=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction, Meta]]
|
||||
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 action objects for a volume.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -38,8 +53,11 @@ class BoundVolume(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions_list(self, status, sort, page, per_page)
|
||||
|
||||
def get_actions(self, status=None, sort=None):
|
||||
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a volume.
|
||||
|
||||
:param status: List[str] (optional)
|
||||
|
@ -50,8 +68,11 @@ class BoundVolume(BoundModelBase):
|
|||
"""
|
||||
return self._client.get_actions(self, status, sort)
|
||||
|
||||
def update(self, name=None, labels=None):
|
||||
# type: (Optional[str], Optional[Dict[str, str]]) -> BoundAction
|
||||
def update(
|
||||
self,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundVolume:
|
||||
"""Updates the volume properties.
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -62,16 +83,18 @@ class BoundVolume(BoundModelBase):
|
|||
"""
|
||||
return self._client.update(self, name, labels)
|
||||
|
||||
def delete(self):
|
||||
# type: () -> BoundAction
|
||||
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.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
return self._client.delete(self)
|
||||
|
||||
def attach(self, server, automount=None):
|
||||
# type: (Union[Server, BoundServer], Optional[bool]) -> BoundAction
|
||||
def attach(
|
||||
self,
|
||||
server: Server | BoundServer,
|
||||
automount: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Attaches a volume to a server. Works only if the server is in the same location as the volume.
|
||||
|
||||
:param server: :class:`BoundServer <hcloud.servers.client.BoundServer>` or :class:`Server <hcloud.servers.domain.Server>`
|
||||
|
@ -80,16 +103,14 @@ class BoundVolume(BoundModelBase):
|
|||
"""
|
||||
return self._client.attach(self, server, automount)
|
||||
|
||||
def detach(self):
|
||||
# type: () -> BoundAction
|
||||
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.
|
||||
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
return self._client.detach(self)
|
||||
|
||||
def resize(self, size):
|
||||
# type: (int) -> BoundAction
|
||||
def resize(self, size: int) -> BoundAction:
|
||||
"""Changes the size of a volume. Note that downsizing a volume is not possible.
|
||||
|
||||
:param size: int
|
||||
|
@ -98,8 +119,7 @@ class BoundVolume(BoundModelBase):
|
|||
"""
|
||||
return self._client.resize(self, size)
|
||||
|
||||
def change_protection(self, delete=None):
|
||||
# type: (Optional[bool]) -> BoundAction
|
||||
def change_protection(self, delete: bool | None = None) -> BoundAction:
|
||||
"""Changes the protection configuration of a volume.
|
||||
|
||||
:param delete: boolean
|
||||
|
@ -109,11 +129,15 @@ class BoundVolume(BoundModelBase):
|
|||
return self._client.change_protection(self, delete)
|
||||
|
||||
|
||||
class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
||||
results_list_attribute_name = "volumes"
|
||||
class VolumesPageResult(NamedTuple):
|
||||
volumes: list[BoundVolume]
|
||||
meta: Meta | None
|
||||
|
||||
def get_by_id(self, id):
|
||||
# type: (int) -> volumes.client.BoundVolume
|
||||
|
||||
class VolumesClient(ClientEntityBase):
|
||||
_client: Client
|
||||
|
||||
def get_by_id(self, id: int) -> BoundVolume:
|
||||
"""Get a specific volume by its id
|
||||
|
||||
:param id: int
|
||||
|
@ -123,9 +147,13 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
return BoundVolume(self, response["volume"])
|
||||
|
||||
def get_list(
|
||||
self, name=None, label_selector=None, page=None, per_page=None, status=None
|
||||
):
|
||||
# type: (Optional[str], Optional[str], Optional[int], Optional[int], Optional[List[str]]) -> PageResults[List[BoundVolume], Meta]
|
||||
self,
|
||||
name: str | None = None,
|
||||
label_selector: str | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> VolumesPageResult:
|
||||
"""Get a list of volumes from this account
|
||||
|
||||
:param name: str (optional)
|
||||
|
@ -140,7 +168,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundVolume <hcloud.volumes.client.BoundVolume>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
params["name"] = name
|
||||
if label_selector is not None:
|
||||
|
@ -156,10 +184,13 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
volumes = [
|
||||
BoundVolume(self, volume_data) for volume_data in response["volumes"]
|
||||
]
|
||||
return self._add_meta_to_result(volumes, response)
|
||||
return VolumesPageResult(volumes, Meta.parse_meta(response))
|
||||
|
||||
def get_all(self, label_selector=None, status=None):
|
||||
# type: (Optional[str], Optional[List[str]]) -> List[BoundVolume]
|
||||
def get_all(
|
||||
self,
|
||||
label_selector: str | None = None,
|
||||
status: list[str] | None = None,
|
||||
) -> list[BoundVolume]:
|
||||
"""Get all volumes from this account
|
||||
|
||||
:param label_selector:
|
||||
|
@ -168,29 +199,31 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Can be used to filter volumes by their status. The response will only contain volumes matching the status.
|
||||
:return: List[:class:`BoundVolume <hcloud.volumes.client.BoundVolume>`]
|
||||
"""
|
||||
return super().get_all(label_selector=label_selector, status=status)
|
||||
return self._iter_pages(
|
||||
self.get_list,
|
||||
label_selector=label_selector,
|
||||
status=status,
|
||||
)
|
||||
|
||||
def get_by_name(self, name):
|
||||
# type: (str) -> BoundVolume
|
||||
def get_by_name(self, name: str) -> BoundVolume | None:
|
||||
"""Get volume by name
|
||||
|
||||
:param name: str
|
||||
Used to get volume by name.
|
||||
:return: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>`
|
||||
"""
|
||||
return super().get_by_name(name)
|
||||
return self._get_first_by(name=name)
|
||||
|
||||
def create(
|
||||
self,
|
||||
size, # type: int
|
||||
name, # type: str
|
||||
labels=None, # type: Optional[str]
|
||||
location=None, # type: Optional[Location]
|
||||
server=None, # type: Optional[Server],
|
||||
automount=None, # type: Optional[bool],
|
||||
format=None, # type: Optional[str],
|
||||
):
|
||||
# type: (...) -> CreateVolumeResponse
|
||||
size: int,
|
||||
name: str,
|
||||
labels: str | None = None,
|
||||
location: Location | None = None,
|
||||
server: Server | None = None,
|
||||
automount: bool | None = None,
|
||||
format: str | None = None,
|
||||
) -> CreateVolumeResponse:
|
||||
"""Creates a new volume attached to a server.
|
||||
|
||||
:param size: int
|
||||
|
@ -214,7 +247,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
if not (bool(location) ^ bool(server)):
|
||||
raise ValueError("only one of server or location must be provided")
|
||||
|
||||
data = {"name": name, "size": size}
|
||||
data: dict[str, Any] = {"name": name, "size": size}
|
||||
if labels is not None:
|
||||
data["labels"] = labels
|
||||
if location is not None:
|
||||
|
@ -240,9 +273,13 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
return result
|
||||
|
||||
def get_actions_list(
|
||||
self, volume, status=None, sort=None, page=None, per_page=None
|
||||
):
|
||||
# type: (Volume, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta]
|
||||
self,
|
||||
volume: Volume | BoundVolume,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
page: int | None = None,
|
||||
per_page: int | None = None,
|
||||
) -> ActionsPageResult:
|
||||
"""Returns all action objects for a volume.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -256,7 +293,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
Specifies how many results are returned by page
|
||||
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
|
||||
"""
|
||||
params = {}
|
||||
params: dict[str, Any] = {}
|
||||
if status is not None:
|
||||
params["status"] = status
|
||||
if sort is not None:
|
||||
|
@ -275,10 +312,14 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
BoundAction(self._client.actions, action_data)
|
||||
for action_data in response["actions"]
|
||||
]
|
||||
return add_meta_to_result(actions, response, "actions")
|
||||
return ActionsPageResult(actions, Meta.parse_meta(response))
|
||||
|
||||
def get_actions(self, volume, status=None, sort=None):
|
||||
# type: (Union[Volume, BoundVolume], Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
|
||||
def get_actions(
|
||||
self,
|
||||
volume: Volume | BoundVolume,
|
||||
status: list[str] | None = None,
|
||||
sort: list[str] | None = None,
|
||||
) -> list[BoundAction]:
|
||||
"""Returns all action objects for a volume.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -288,10 +329,19 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
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 <hcloud.actions.client.BoundAction>`]
|
||||
"""
|
||||
return super().get_actions(volume, status=status, sort=sort)
|
||||
return self._iter_pages(
|
||||
self.get_actions_list,
|
||||
volume,
|
||||
status=status,
|
||||
sort=sort,
|
||||
)
|
||||
|
||||
def update(self, volume, name=None, labels=None):
|
||||
# type:(Union[Volume, BoundVolume], Optional[str], Optional[Dict[str, str]]) -> BoundVolume
|
||||
def update(
|
||||
self,
|
||||
volume: Volume | BoundVolume,
|
||||
name: str | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
) -> BoundVolume:
|
||||
"""Updates the volume properties.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -301,7 +351,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
User-defined labels (key-value pairs)
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if name is not None:
|
||||
data.update({"name": name})
|
||||
if labels is not None:
|
||||
|
@ -313,8 +363,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundVolume(self, response["volume"])
|
||||
|
||||
def delete(self, volume):
|
||||
# type: (Union[Volume, BoundVolume]) -> BoundAction
|
||||
def delete(self, volume: Volume | BoundVolume) -> 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.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -323,8 +372,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
self._client.request(url=f"/volumes/{volume.id}", method="DELETE")
|
||||
return True
|
||||
|
||||
def resize(self, volume, size):
|
||||
# type: (Union[Volume, BoundVolume], int) -> BoundAction
|
||||
def resize(self, volume: Volume | BoundVolume, size: int) -> BoundAction:
|
||||
"""Changes the size of a volume. Note that downsizing a volume is not possible.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -339,8 +387,12 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundAction(self._client.actions, data["action"])
|
||||
|
||||
def attach(self, volume, server, automount=None):
|
||||
# type: (Union[Volume, BoundVolume], Union[Server, BoundServer], Optional[bool]) -> BoundAction
|
||||
def attach(
|
||||
self,
|
||||
volume: Volume | BoundVolume,
|
||||
server: Server | BoundServer,
|
||||
automount: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Attaches a volume to a server. Works only if the server is in the same location as the volume.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -348,7 +400,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
:param automount: boolean
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {"server": server.id}
|
||||
data: dict[str, Any] = {"server": server.id}
|
||||
if automount is not None:
|
||||
data["automount"] = automount
|
||||
|
||||
|
@ -359,8 +411,7 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundAction(self._client.actions, data["action"])
|
||||
|
||||
def detach(self, volume):
|
||||
# type: (Union[Volume, BoundVolume]) -> BoundAction
|
||||
def detach(self, volume: Volume | BoundVolume) -> BoundAction:
|
||||
"""Detaches a volume from the server it’s attached to. You may attach it to a server again at a later time.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -372,8 +423,11 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
)
|
||||
return BoundAction(self._client.actions, data["action"])
|
||||
|
||||
def change_protection(self, volume, delete=None):
|
||||
# type: (Union[Volume, BoundVolume], Optional[bool], Optional[bool]) -> BoundAction
|
||||
def change_protection(
|
||||
self,
|
||||
volume: Volume | BoundVolume,
|
||||
delete: bool | None = None,
|
||||
) -> BoundAction:
|
||||
"""Changes the protection configuration of a volume.
|
||||
|
||||
:param volume: :class:`BoundVolume <hcloud.volumes.client.BoundVolume>` or :class:`Volume <hcloud.volumes.domain.Volume>`
|
||||
|
@ -381,14 +435,12 @@ class VolumesClient(ClientEntityBase, GetEntityByNameMixin):
|
|||
If True, prevents the volume from being deleted
|
||||
:return: :class:`BoundAction <hcloud.actions.client.BoundAction>`
|
||||
"""
|
||||
data = {}
|
||||
data: dict[str, Any] = {}
|
||||
if delete is not None:
|
||||
data.update({"delete": delete})
|
||||
|
||||
response = self._client.request(
|
||||
url="/volumes/{volume_id}/actions/change_protection".format(
|
||||
volume_id=volume.id
|
||||
),
|
||||
url=f"/volumes/{volume.id}/actions/change_protection",
|
||||
method="POST",
|
||||
json=data,
|
||||
)
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
from dateutil.parser import isoparse
|
||||
except ImportError:
|
||||
isoparse = None
|
||||
|
||||
from ..core.domain import BaseDomain, DomainIdentityMixin
|
||||
from ..core import BaseDomain, DomainIdentityMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..actions import BoundAction
|
||||
from ..locations import BoundLocation, Location
|
||||
from ..servers import BoundServer, Server
|
||||
from .client import BoundVolume
|
||||
|
||||
|
||||
class Volume(BaseDomain, DomainIdentityMixin):
|
||||
|
@ -54,17 +64,17 @@ class Volume(BaseDomain, DomainIdentityMixin):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
id,
|
||||
name=None,
|
||||
server=None,
|
||||
created=None,
|
||||
location=None,
|
||||
size=None,
|
||||
linux_device=None,
|
||||
format=None,
|
||||
protection=None,
|
||||
labels=None,
|
||||
status=None,
|
||||
id: int,
|
||||
name: str | None = None,
|
||||
server: Server | BoundServer | None = None,
|
||||
created: str | None = None,
|
||||
location: Location | BoundLocation | None = None,
|
||||
size: int | None = None,
|
||||
linux_device: str | None = None,
|
||||
format: str | None = None,
|
||||
protection: dict | None = None,
|
||||
labels: dict[str, str] | None = None,
|
||||
status: str | None = None,
|
||||
):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -94,9 +104,9 @@ class CreateVolumeResponse(BaseDomain):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
volume, # type: BoundVolume
|
||||
action, # type: BoundAction
|
||||
next_actions, # type: List[BoundAction]
|
||||
volume: BoundVolume,
|
||||
action: BoundAction,
|
||||
next_actions: list[BoundAction],
|
||||
):
|
||||
self.volume = volume
|
||||
self.action = action
|
||||
|
|
|
@ -19,7 +19,7 @@ from textwrap import dedent
|
|||
logger = logging.getLogger("vendor")
|
||||
|
||||
HCLOUD_SOURCE_URL = "https://github.com/hetznercloud/hcloud-python"
|
||||
HCLOUD_VERSION = "v1.26.0"
|
||||
HCLOUD_VERSION = "v1.27.1"
|
||||
HCLOUD_VENDOR_PATH = "plugins/module_utils/vendor/hcloud"
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue