Skip to content

Commit

Permalink
Add balancers API funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
LulzLoL231 committed Feb 12, 2023
1 parent 7b17615 commit 02d80f4
Show file tree
Hide file tree
Showing 10 changed files with 837 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ print(account_status)
- [x] Аккаунт
- [x] Базы данных
- [ ] Балансировщики
- [x] Балансировщики
- [x] Выделенные серверы
- [ ] Домены
- [ ] Облачные серверы
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "timeweb-cloud"
version = "0.4.1"
version = "0.5.0"
description = "Timeweb Cloud API wrapper"
authors = ["Maxim Mosin <max@mosin.pw>"]
license = "MIT"
Expand Down Expand Up @@ -38,7 +38,7 @@ requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.bumpver]
current_version = "0.4.1"
current_version = "0.5.0"
version_pattern = "MAJOR.MINOR.PATCH"
commit_message = "Bump version {old_version} -> {new_version}"
commit = false
Expand Down
2 changes: 1 addition & 1 deletion src/timeweb/__meta.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
'''Timeweb Cloud package metadata'''
__version__ = '0.4.1'
__version__ = '0.5.0'
__author__ = 'Maxim Mosin <max@mosin.pw>'
3 changes: 3 additions & 0 deletions src/timeweb/async_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .dedics import DedicsAPI
from .account import AccountAPI
from .ssh_keys import SSHKeysAPI
from .balancers import BalancersAPI


class Servers:
Expand Down Expand Up @@ -42,6 +43,7 @@ class AsyncTimeweb:
s3 (BucketsAPI): API для работы с S3-хранилищами.
dbs (DatabasesAPI): API для работы с базами данных.
servers (Servers): API для работы с серверами.
balancers (BalancersAPI): API для работы с балансировщиками.
'''

def __init__(self, token: str, client: AsyncClient | None = None):
Expand All @@ -59,3 +61,4 @@ def __init__(self, token: str, client: AsyncClient | None = None):
self.s3 = BucketsAPI(token, client)
self.dbs = DatabasesAPI(token, client)
self.servers = Servers(token, client)
self.balancers = BalancersAPI(token, client)
344 changes: 344 additions & 0 deletions src/timeweb/async_api/balancers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
# -*- coding: utf-8 -*-
'''Методы API для работы с балансировщиками.
Балансировщик позволяет распределять входящий трафик между несколькими серверами для повышения доступности и отказоустойчивости вашего сервиса.
Документация: https://timeweb.cloud/api-docs#tag/Balansirovshiki'''
import logging
from ipaddress import IPv4Address, IPv6Address

from httpx import AsyncClient

from .base import BaseAsyncClient
from ..schemas import balancers as schemas


class BalancersAPI(BaseAsyncClient):
'''Клиент для работы с API балансировщиками Timeweb Cloud'''

def __init__(self, token: str, client: AsyncClient | None = None):
'''Инициализация клиента.
Args:
token (str): API токен.
client (AsyncClient | None, optional): HTTPX клиент. Defaults to None.
'''
super().__init__(token, client)
self.log = logging.getLogger('timeweb')

async def get_balancers(self) -> schemas.BalancersResponse:
'''Получить список балансировщиков.
Returns:
BalancersResponse: Список балансировщиков.
'''
balancers = await self._request(
'GET', '/balancers'
)
return schemas.BalancersResponse(**balancers.json())

async def create(
self, name: str, algo: schemas.BalancerAlgorithm | str, is_sticky: bool,
is_use_proxy: bool, is_ssl: bool, is_keepalive: bool, port: int,
proto: schemas.Protocol | str, path: str, inter: int, timeout: int,
fall: int, rise: int, preset_id: int
) -> schemas.BalancerResponse:
'''Создать балансировщик.
Args:
name (str): Название балансировщика.
algo (BalancerAlgorithm | str): Алгоритм переключений балансировщика.
is_sticky (bool): Сохраняется ли сессия.
is_use_proxy (bool): Выступает ли балансировщик в качестве прокси.
is_ssl (bool): Требуется ли перенаправление на SSL.
is_keepalive (bool): Выдает ли балансировщик сигнал о проверке жизнеспособности.
port (int): Порт балансировщика.
proto (Protocol | str): Протокол балансировщика.
path (str): Адрес балансировщика.
inter (int): Интервал проверки.
timeout (int): Таймаут ответа балансировщика.
fall (int): Порог количества ошибок.
rise (int): Порог количества успешных проверок.
preset_id (int): UID тарифа балансировщика.
Returns:
BalancerResponse: Балансировщик.
'''
data = {
'name': name,
'is_sticky': is_sticky,
'is_use_proxy': is_use_proxy,
'is_ssl': is_ssl,
'is_keepalive': is_keepalive,
'port': port,
'path': path,
'inter': inter,
'timeout': timeout,
'fall': fall,
'rise': rise,
'preset_id': preset_id
}
if isinstance(algo, schemas.BalancerAlgorithm):
data['algo'] = algo.value
else:
data['algo'] = algo
if isinstance(proto, schemas.Protocol):
data['proto'] = proto.value
else:
data['proto'] = proto
balancer = await self._request(
'POST', '/balancers', json=data
)
return schemas.BalancerResponse(**balancer.json())

async def get(self, balancer_id: int) -> schemas.BalancerResponse:
'''Получить балансировщик.
Args:
balancer_id (int): UID балансировщика.
Returns:
BalancerResponse: Балансировщик.
'''
balancer = await self._request(
'GET', f'/balancers/{balancer_id}'
)
return schemas.BalancerResponse(**balancer.json())

async def update(
self, balancer_id: int, name: str | None = None,
algo: schemas.BalancerAlgorithm | str | None = None,
is_sticky: bool | None = None, is_use_proxy: bool | None = None,
is_ssl: bool | None = None, is_keepalive: bool | None = None,
port: int | None = None, proto: schemas.Protocol | str | None = None,
path: str | None = None, inter: int | None = None,
timeout: int | None = None, fall: int | None = None,
rise: int | None = None, preset_id: int | None = None
) -> schemas.BalancerResponse:
'''Обновить балансировщик.
Args:
balancer_id (int): UID балансировщика.
name (str | None, optional): Название балансировщика. Defaults to None.
algo (BalancerAlgorithm | str | None, optional): Алгоритм переключений балансировщика. Defaults to None.
is_sticky (bool | None, optional): Сохраняется ли сессия. Defaults to None.
is_use_proxy (bool | None, optional): Выступает ли балансировщик в качестве прокси. Defaults to None.
is_ssl (bool | None, optional): Требуется ли перенаправление на SSL. Defaults to None.
is_keepalive (bool | None, optional): Выдает ли балансировщик сигнал о проверке жизнеспособности. Defaults to None.
port (int | None, optional): Порт балансировщика. Defaults to None.
proto (Protocol | str | None, optional): Протокол балансировщика. Defaults to None.
path (str | None, optional): Адрес балансировщика. Defaults to None.
inter (int | None, optional): Интервал проверки. Defaults to None.
timeout (int | None, optional): Таймаут ответа балансировщика. Defaults to None.
fall (int | None, optional): Порог количества ошибок. Defaults to None.
rise (int | None, optional): Порог количества успешных проверок. Defaults to None.
preset_id (int | None, optional): UID тарифа балансировщика. Defaults to None.
Returns:
BalancerResponse: Балансировщик.
'''
data: dict[str, str | int] = {}
if name is not None:
data['name'] = name
if algo is not None:
if isinstance(algo, schemas.BalancerAlgorithm):
data['algo'] = algo.value
else:
data['algo'] = algo
if is_sticky:
data['is_sticky'] = is_sticky
if is_use_proxy:
data['is_use_proxy'] = is_use_proxy
if is_ssl:
data['is_ssl'] = is_ssl
if is_keepalive:
data['is_keepalive'] = is_keepalive
if port is not None:
data['port'] = port
if proto is not None:
if isinstance(proto, schemas.Protocol):
data['proto'] = proto.value
else:
data['proto'] = proto
if path is not None:
data['path'] = path
if inter is not None:
data['inter'] = inter
if timeout is not None:
data['timeout'] = timeout
if fall is not None:
data['fall'] = fall
if rise is not None:
data['rise'] = rise
if preset_id is not None:
data['preset_id'] = preset_id
balancer = await self._request(
'PATCH', f'/balancers/{balancer_id}', json=data
)
return schemas.BalancerResponse(**balancer.json())

async def delete(self, balancer_id: int) -> bool:
'''Удалить балансировщик.
Args:
balancer_id (int): UID балансировщика.
Returns:
bool: Успешность удаления.
'''
await self._request(
'DELETE', f'/balancers/{balancer_id}'
)
return True

async def get_balancer_ips(self, balancer_id: int) -> schemas.BalancerIPsResponse:
'''Получить IP балансировщика.
Args:
balancer_id (int): UID IP балансировщика.
Returns:
BalancerIPsResponse: IP адреса балансировщика.
'''
balancer_ips = await self._request(
'GET', f'/balancers/{balancer_id}/ips'
)
return schemas.BalancerIPsResponse(**balancer_ips.json())

async def add_balancer_ips(
self, balancer_id: int, ips: list[str | IPv4Address | IPv6Address]
) -> bool:
'''Добавить IP адреса балансировщика.
Args:
balancer_id (int): UID балансировщика.
ips (list[str | IPv4Address | IPv6Address]): IP адреса.
Returns:
bool: IP адреса добавлены.
'''
resp = await self._request(
'POST', f'/balancers/{balancer_id}/ips', json={'ips': ips}
)
return resp.is_success

async def delete_balancer_ips(
self, balancer_id: int, ips: list[str | IPv4Address | IPv6Address]
) -> bool:
'''Удаление IP адресов балансировщика.
Args:
balancer_id (int): UID балансировщика.
ips (list[str | IPv4Address | IPv6Address]): IP адреса.
Returns:
bool: IP адреса удалены.
'''
resp = await self._request(
'DELETE', f'/balancers/{balancer_id}/ips', json={'ips': ips}
)
return resp.is_success

async def get_balancer_rules(self, balancer_id: int) -> schemas.BalancerRulesResponse:
'''Получить правила балансировщика.
Args:
balancer_id (int): UID балансировщика.
Returns:
BalancerRulesResponse: Правила балансировщика.
'''
balancer_rules = await self._request(
'GET', f'/balancers/{balancer_id}/rules'
)
return schemas.BalancerRulesResponse(**balancer_rules.json())

async def add_balancer_rule(
self, balancer_id: int, balancer_proto: schemas.Protocol | str,
balancer_port: int, server_proto: schemas.Protocol | str,
server_port: int
) -> schemas.BalancerRuleResponse:
'''Добавить правило балансировщика.
Args:
balancer_id (int): UID балансировщика.
balancer_proto (Protocol | str): Протокол балансировщика.
balancer_port (int): Порт балансировщика.
server_proto (Protocol | str): Протокол сервера.
server_port (int): Порт сервера.
Returns:
BalancerRuleResponse: Добавленное правило.
'''
data: dict[str, str | int] = {}
if isinstance(balancer_proto, schemas.Protocol):
data['balancer_proto'] = balancer_proto.value
else:
data['balancer_proto'] = balancer_proto
data['balancer_port'] = balancer_port
if isinstance(server_proto, schemas.Protocol):
data['server_proto'] = server_proto.value
else:
data['server_proto'] = server_proto
data['server_port'] = server_port
balancer_rule = await self._request(
'POST', f'/balancers/{balancer_id}/rules', json=data
)
return schemas.BalancerRuleResponse(**balancer_rule.json())

async def update_balancer_rule(
self, balancer_id: int, rule_id: int,
balancer_proto: schemas.Protocol | str, balancer_port: int,
server_proto: schemas.Protocol | str, server_port: int
) -> schemas.BalancerRuleResponse:
'''Добавить правило балансировщика.
Args:
balancer_id (int): UID балансировщика.
rule_id (int): UID правила.
balancer_proto (Protocol | str): Протокол балансировщика.
balancer_port (int): Порт балансировщика.
server_proto (Protocol | str): Протокол сервера.
server_port (int): Порт сервера.
Returns:
BalancerRuleResponse: Обнавлённое правило.
'''
data: dict[str, str | int] = {}
if isinstance(balancer_proto, schemas.Protocol):
data['balancer_proto'] = balancer_proto.value
else:
data['balancer_proto'] = balancer_proto
data['balancer_port'] = balancer_port
if isinstance(server_proto, schemas.Protocol):
data['server_proto'] = server_proto.value
else:
data['server_proto'] = server_proto
data['server_port'] = server_port
balancer_rule = await self._request(
'PATCH', f'/balancers/{balancer_id}/rules/{rule_id}', json=data
)
return schemas.BalancerRuleResponse(**balancer_rule.json())

async def delete_balancer_rule(self, balancer_id: int, rule_id: int) -> bool:
'''Удалить правило балансировщика.
Args:
balancer_id (int): UID балансировщика.
rule_id (int): UID правила.
Returns:
bool: Правило удалено.
'''
resp = await self._request(
'DELETE', f'/balancers/{balancer_id}/rules/{rule_id}'
)
return resp.is_success

async def get_presets(self) -> schemas.BalancerPresetsResponse:
'''Получить список тарифов балансировщиков.
Returns:
BalancerPresetsResponse: Список тарифов.
'''
balancer_presets = await self._request('GET', '/presets/balancers')
return schemas.BalancerPresetsResponse(**balancer_presets.json())
Loading

0 comments on commit 02d80f4

Please sign in to comment.