-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #67 from Aerodisk/backup/main
Добавление нового модуля для управления резервным копированием данных с использованием Restic.
- Loading branch information
Showing
35 changed files
with
2,013 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
"""Common schemas for standardizing API responses. | ||
This module defines a generic Pydantic schema for creating consistent | ||
API response structures across the application. | ||
Classes: | ||
BaseResponse: A generic schema for API responses, supporting customizable | ||
data, status, and error messages. | ||
""" | ||
|
||
from typing import Generic, TypeVar, Optional | ||
|
||
from pydantic import BaseModel | ||
|
||
T = TypeVar('T') | ||
|
||
|
||
class BaseResponse(BaseModel, Generic[T]): | ||
"""Generic schema for API responses. | ||
This schema is designed to standardize API responses by including | ||
a status, optional data, and an optional error message. | ||
Attributes: | ||
status (str): The status of the response (e.g., "success", "error"). | ||
data (Optional[T]): The data payload of the response, if applicable. | ||
error (Optional[str]): An error message, if applicable. | ||
""" | ||
|
||
status: str | ||
data: Optional[T] = None | ||
error: Optional[str] = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"""Module for managing backup-related operations in the service layer. | ||
The module includes an interface definition for the backup service layer | ||
manager, which outlines the methods that should be implemented by any class | ||
responsible for managing backup operations. | ||
""" | ||
|
||
from typing import Protocol | ||
|
||
|
||
class BackupServiceLayerManagerProtocolInterface(Protocol): | ||
"""Interface for the BackupServiceLayerManager. | ||
This interface defines the methods that should be implemented by any class | ||
that manages backup-related operations in the service layer. | ||
""" | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
"""Repository module for managing PostgreSQL databases. | ||
This module defines an abstract base class for database repositories and | ||
provides a concrete implementation using SQLAlchemy to manage PostgreSQL | ||
databases. It includes methods for terminating connections, dropping databases, | ||
creating databases | ||
""" | ||
|
||
from abc import ABCMeta, abstractmethod | ||
from typing import TYPE_CHECKING | ||
|
||
from sqlalchemy import text, create_engine | ||
|
||
from openvair.config import database, get_postgres_uri | ||
|
||
if TYPE_CHECKING: | ||
from sqlalchemy.orm import Session | ||
|
||
|
||
class AbstractRepository(metaclass=ABCMeta): | ||
"""Abstract base class for database repositories. | ||
Defines the interface for database operations such as terminating | ||
connections, dropping databases, creating databases, and restoring data. | ||
""" | ||
|
||
@abstractmethod | ||
def terminate_all_connections(self, db_name: str) -> None: | ||
"""Terminate all active connections to a specified database. | ||
Args: | ||
db_name (str): Name of the database whose connections should be | ||
terminated. | ||
""" | ||
... | ||
|
||
@abstractmethod | ||
def drop_db(self, db_name: str) -> None: | ||
"""Drop a specified database. | ||
Args: | ||
db_name (str): Name of the database to drop. | ||
""" | ||
... | ||
|
||
@abstractmethod | ||
def create_db(self, db_name: str) -> None: | ||
"""Create a new database. | ||
Args: | ||
db_name (str): Name of the database to create. | ||
""" | ||
... | ||
|
||
|
||
class SqlAlchemyRepository(AbstractRepository): | ||
"""SQLAlchemy implementation of a database repository. | ||
This class provides concrete implementations of database operations | ||
using SQLAlchemy, tailored for PostgreSQL. | ||
Attributes: | ||
session (Session): SQLAlchemy session for database interactions. | ||
engine (Engine): SQLAlchemy engine for executing database commands. | ||
""" | ||
def __init__(self, session: 'Session'): | ||
"""Initialize the SQLAlchemy repository. | ||
Args: | ||
session (Session): SQLAlchemy session for database interactions. | ||
""" | ||
self.session: Session = session | ||
self.engine = create_engine( | ||
get_postgres_uri().replace( | ||
database['db_name'], 'postgres' | ||
) # for connection to 'postgres' db, instead 'openvair' | ||
) | ||
|
||
def terminate_all_connections(self, db_name: str) -> None: | ||
"""Terminate all active connections to a specified database. | ||
Uses a SQL query to terminate all connections to the specified database, | ||
except the current session. | ||
Args: | ||
db_name (str): Name of the database whose connections should be | ||
terminated. | ||
""" | ||
with self.session.connection() as conn: | ||
conn.execute( | ||
text(""" | ||
SELECT pg_terminate_backend(pg_stat_activity.pid) | ||
FROM pg_stat_activity | ||
WHERE pg_stat_activity.datname = :db_name | ||
AND pid <> pg_backend_pid(); | ||
"""), | ||
{'db_name': db_name}, | ||
) | ||
|
||
def drop_db(self, db_name: str) -> None: | ||
"""Drop a specified database. | ||
Executes a SQL command to drop the database. All connections to the | ||
database are terminated before the drop operation. | ||
Args: | ||
db_name (str): Name of the database to drop. | ||
""" | ||
with self.engine.connect().execution_options( | ||
isolation_level='AUTOCOMMIT' | ||
) as conn: # connect withot transaction | ||
# Stop all connections | ||
conn.execute( | ||
text(""" | ||
SELECT pg_terminate_backend(pg_stat_activity.pid) | ||
FROM pg_stat_activity | ||
WHERE pg_stat_activity.datname = :db_name | ||
AND pid <> pg_backend_pid(); | ||
"""), | ||
{'db_name': db_name}, | ||
) | ||
|
||
conn.execute(text(f'DROP DATABASE "{db_name}";')) | ||
|
||
def create_db(self, db_name: str) -> None: | ||
"""Create a new database. | ||
Executes a SQL command to create a new database. | ||
Args: | ||
db_name (str): Name of the database to create. | ||
""" | ||
with self.engine.connect().execution_options( | ||
isolation_level='AUTOCOMMIT' | ||
) as conn: # Connect without transaction | ||
conn.execute(text(f'CREATE DATABASE "{db_name}";')) | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""Module for custom exceptions in the restic adapters.""" | ||
|
||
from typing import Any | ||
|
||
from openvair.abstracts.base_exception import BaseCustomException | ||
|
||
|
||
class ResticError(BaseCustomException): | ||
"""Base errro class for error in restic adapter""" | ||
|
||
def __init__(self, message: str, *args: Any): # noqa: ANN401 | ||
"""Initialize ResticAdapterException""" | ||
super().__init__(message, args) | ||
|
||
|
||
class ResticExecutorError(ResticError): | ||
"""Raises when execution failed""" | ||
|
||
... | ||
|
||
|
||
class ResticInitRepoError(ResticError): | ||
"""Raises when getting error while initialize restic repository""" | ||
|
||
... | ||
|
||
|
||
class ResticBackupError(ResticError): | ||
"""Raises when error while backup restic operation""" | ||
|
||
... | ||
|
||
class ResticRestoreError(ResticError): | ||
"""Raises when error while restoring restic operation""" | ||
|
||
... |
Oops, something went wrong.