Skip to content

Commit

Permalink
Add dbs api funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
LulzLoL231 committed Feb 9, 2023
1 parent f5ffe8b commit 22680d2
Show file tree
Hide file tree
Showing 11 changed files with 716 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ print(account_status)
> В планах добавить все методы API, но на текущий момент доступны только некоторые из них.
- [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.2.0"
version = "0.3.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.2.0"
current_version = "0.3.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.2.0'
__version__ = '0.3.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 @@ -5,6 +5,7 @@
from httpx import AsyncClient

from .s3 import BucketsAPI
from .dbs import DatabasesAPI
from .tokens import TokensAPI
from .images import ImagesAPI
from .account import AccountAPI
Expand All @@ -20,6 +21,7 @@ class AsyncTimeweb:
ssh_keys (SSHKeysAPI): API для работы с SSH ключами.
images (ImagesAPI): API для работы с образами.
s3 (BucketsAPI): API для работы с S3-хранилищами.
dbs (DatabasesAPI): API для работы с базами данных.
'''

def __init__(self, token: str, client: AsyncClient | None = None):
Expand All @@ -35,3 +37,4 @@ def __init__(self, token: str, client: AsyncClient | None = None):
self.ssh_keys = SSHKeysAPI(token, client)
self.images = ImagesAPI(token, client)
self.s3 = BucketsAPI(token, client)
self.dbs = DatabasesAPI(token, client)
240 changes: 240 additions & 0 deletions src/timeweb/async_api/dbs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
# -*- coding: utf-8 -*-
'''Методы API для работы с API образов.
Облачная база данных, или База данных как сервис (DBaaS) —
облачное решение для хранения структурированных данных и управления ими.
DBaaS обеспечивает полностью автоматизированную, гибкую и масштабируемую
платформу для работы с базами данных.
Документация: https://timeweb.cloud/api-docs#tag/Bazy-dannyh'''
import logging

from httpx import AsyncClient

from .base import BaseAsyncClient
from ..schemas import dbs as schemas


class DatabasesAPI(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_databases(self) -> schemas.DBArray:
'''Получить список баз данных.
Returns:
schemas.DBArray: Список баз данных.
'''
dbs = await self._request(
'GET', '/dbs'
)
return schemas.DBArray(**dbs.json())

async def create(
self,
password: str,
name: str,
type: schemas.DBType | str,
preset_id: int,
login: str | None = None,
hash_type: schemas.DBHashType | str | None = None,
config_parameters: schemas.DBConfigParameters | None = None
) -> schemas.DatabaseResponse:
'''Создать базу данных.
Args:
password (str): Пароль для доступа к базе данных.
name (str): Название базы данных.
type (schemas.DBType | str): Тип базы данных.
preset_id (int): ID пресета.
login (str | None, optional): Логин для доступа к базе данных.
Defaults to None.
hash_type (schemas.DBHashType | str | None, optional): Тип хэша.
Defaults to None.
config_parameters (schemas.DBConfigParameters | None, optional):
Параметры конфигурации. Defaults to None.
Returns:
schemas.DatabaseResponse: Ответ от API.
'''
data = {
'password': password,
'name': name,
'type': type,
'preset_id': preset_id
}
if login:
data['login'] = login
if hash_type:
if isinstance(hash_type, schemas.DBHashType):
data['hash_type'] = hash_type.value
else:
data['hash_type'] = hash_type
if config_parameters:
data['config_parameters'] = config_parameters.dict()
db = await self._request(
'POST', '/dbs', json=data
)
return schemas.DatabaseResponse(**db.json())

async def get(self, db_id: int) -> schemas.DatabaseResponse:
'''Получить информацию о базе данных.
Args:
db_id (int): ID базы данных.
Returns:
schemas.DatabaseResponse: Ответ от API.
'''
db = await self._request(
'GET', f'/dbs/{db_id}'
)
return schemas.DatabaseResponse(**db.json())

async def update(
self,
db_id: int,
password: str | None = None,
name: str | None = None,
preset_id: int | None = None,
config_parameters: schemas.DBConfigParameters | None = None,
is_external_ip: bool | None = None
) -> schemas.DatabaseResponse:
'''Обновить базу данных.
Args:
db_id (int): ID базы данных.
password (str | None, optional): Пароль для доступа к базе данных.
Defaults to None.
name (str | None, optional): Название базы данных. Defaults to None.
preset_id (int | None, optional): ID пресета. Defaults to None.
config_parameters (schemas.DBConfigParameters | None, optional):
Параметры конфигурации. Defaults to None.
is_external_ip (bool | None, optional): Внешний IP. Defaults to None.
Returns:
schemas.DatabaseResponse: Ответ от API.
'''
data: dict[str, str | int | dict] = {}
if password:
data['password'] = password
if name:
data['name'] = name
if preset_id:
data['preset_id'] = preset_id
if config_parameters:
data['config_parameters'] = config_parameters.dict()
if is_external_ip is not None:
data['is_external_ip'] = str(is_external_ip).lower()
db = await self._request(
'PATCH', f'/dbs/{db_id}', json=data
)
return schemas.DatabaseResponse(**db.json())

async def delete(self, db_id: int) -> bool:
'''Удалить базу данных.
Args:
db_id (int): ID базы данных.
Returns:
bool: True, если база данных успешно удалена.
'''
await self._request(
'DELETE', f'/dbs/{db_id}'
)
return True

async def get_backups(
self, db_id: int, limit: int = 100, offset: int = 0
) -> schemas.BackupArray:
'''Получить список бэкапов базы данных.
Args:
db_id (int): ID базы данных.
limit (int, optional): Лимит. Defaults to 100.
offset (int, optional): Смещение. Defaults to 0.
Returns:
schemas.BackupArray: Ответ от API.
'''
backups = await self._request(
'GET', f'/dbs/{db_id}/backups', params={
'limit': limit,
'offset': offset
}
)
return schemas.BackupArray(**backups.json())

async def create_backup(self, db_id: int) -> schemas.BackupResponse:
'''Создать бэкап базы данных.
Args:
db_id (int): ID базы данных.
Returns:
schemas.BackupResponse: Ответ от API.
'''
backup = await self._request(
'POST', f'/dbs/{db_id}/backups'
)
return schemas.BackupResponse(**backup.json())

async def delete_backup(self, db_id: int, backup_id: int) -> bool:
'''Удалить бэкап базы данных.
Args:
db_id (int): ID базы данных.
backup_id (int): ID бэкапа.
Returns:
bool: True, если бэкап успешно удален.
'''
await self._request(
'DELETE', f'/dbs/{db_id}/backups/{backup_id}'
)
return True

async def get_backup(self, db_id: int, backup_id: int) -> schemas.BackupResponse:
'''Получить информацию о бэкапе базы данных.
Args:
db_id (int): ID базы данных.
backup_id (int): ID бэкапа.
Returns:
schemas.BackupResponse: Ответ от API.
'''
backup = await self._request(
'GET', f'/dbs/{db_id}/backups/{backup_id}'
)
return schemas.BackupResponse(**backup.json())

async def recover_from_backup(self, db_id: int, backup_id: int) -> bool:
'''Восстановить базу данных из бэкапа.
Args:
db_id (int): ID базы данных.
backup_id (int): ID бэкапа.
Returns:
bool: True, если база данных успешно восстановлена.
'''
await self._request(
'PUT', f'/dbs/{db_id}/backups/{backup_id}'
)
return True

async def get_presets(self) -> schemas.PresetArray:
'''Получить список пресетов.
Returns:
schemas.PresetArray: Ответ от API.
'''
presets = await self._request(
'GET', '/presets/dbs'
)
return schemas.PresetArray(**presets.json())
6 changes: 6 additions & 0 deletions src/timeweb/schemas/dbs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# flake8: noqa
'''Модели для работы с Базами данных'''
from .dbs import *
from .backups import *
from .presets import *
52 changes: 52 additions & 0 deletions src/timeweb/schemas/dbs/backups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
'''Модели для работы с Бэкапами баз данных'''
from enum import Enum
from datetime import datetime

from pydantic import BaseModel, Field

from ..base import ResponseWithMeta, BaseResponse


class BackupStatus(str, Enum):
'''Статусы бэкапов'''
PRECREATE = 'precreate'
DELETE = 'delete'
SHUTDOWN = 'shutdown'
RECOVER = 'recover'
CREATE = 'create'
FAIL = 'fail'
DONE = 'done'


class BackupType(str, Enum):
'''Типы бэкапов'''
MANUAL = 'manual'
AUTO = 'auto'


class Backup(BaseModel):
'''Бэкап базы данных'''
id: int = Field(..., description='ID бэкапа.')
name: str = Field(..., description='Имя бэкапа.')
comment: str | None = Field(
None, description='Комментарий к бэкапу.'
)
created_at: datetime = Field(
..., description='Дата создания бэкапа.'
)
status: BackupStatus = Field(
..., description='Статус бэкапа.'
)
size: int = Field(..., description='Размер бэкапа (Мб).')
type: BackupType = Field(..., description='Тип бэкапа.')


class BackupArray(ResponseWithMeta):
'''Массив бэкапов'''
backups: list[Backup] = Field(..., description='Массив бэкапов.')


class BackupResponse(BaseResponse):
'''Бэкап'''
backup: Backup = Field(..., description='Бэкап.')
Loading

0 comments on commit 22680d2

Please sign in to comment.