Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Hyper Backup #31

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,39 @@ The ``SynologyDSM`` class can also ``update()`` all APIs at once.
print("--")


Hyper Backup usage
--------------------------

.. code-block:: python

from synology_dsm import SynologyDSM

api = SynologyDSM("<IP/DNS>", "<port>", "<username>", "<password>")
backup = api.backup
backup.update() # First update is required

# Returns a list of all defined backup tasks
backup_tasks = backup.get_all_tasks()

# Print details for each backup task
for task in backup_tasks:
print("---------------------------------------------")
print("Name:", task.name)
print("Task ID:", task.task_id)
print("Encryption enabled:", task.data_enc)
print("Data type:", task.data_type)
print("Dict of objects to backup:", task.source)
print("State:", task.state)
print("Status:", task.status)
print("Target ID:", task.target_id)
print("Target Type:", task.target_type)
print("Transfer Type:", task.transfer_type)
print("Type:", task.type)

# Get details about specific backup task by its task_id
task = backup.get_task(task_id)


Download Station usage
--------------------------

Expand Down
41 changes: 41 additions & 0 deletions src/synology_dsm/api/backup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Synology Backup API models."""
from typing import Any
from typing import Dict

from .const import PROP_TASKID
from .task import SynoBackupTask


class SynoBackup:
"""An implementaion of Synology HyperBackup."""

API_KEY = "SYNO.Backup.*"
API_KEY_TASK = "SYNO.Backup.Task"

def __init__(self, dsm):
"""Initialize HyperBackup."""
self._dsm = dsm
self._data = {}

def update(self):
"""Update backup tasks settings and information from API."""
self._data = {}
task_list = self._dsm.get(self.API_KEY_TASK, "list", max_version=1)["data"].get(
"task_list", []
)
for task in task_list:
backup_task_data = self._dsm.get(
self.API_KEY_TASK,
"get",
{PROP_TASKID: task[PROP_TASKID]},
max_version=1,
)["data"]
self._data[task[PROP_TASKID]] = SynoBackupTask(backup_task_data)

def get_all_tasks(self) -> Dict[str, Dict[str, Any]]:
"""Return a list of all tasks."""
return self._data.values()

def get_task(self, task_id: int) -> Dict[str, Any]:
"""Return task matching task_id."""
return self._data[task_id]
13 changes: 13 additions & 0 deletions src/synology_dsm/api/backup/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Synology HyperBackup API constants."""

PROP_DATA_ENCRYPTION = "data_enc"
PROP_DATA_TYPE = "data_type"
PROP_NAME = "name"
PROP_SOURCE = "source"
PROP_STATE = "state"
PROP_STATUS = "status"
PROP_TARGET_ID = "target_id"
PROP_TARGET_TYPE = "target_type"
PROP_TASKID = "task_id"
PROP_TRANSFER_TYPE = "transfer_type"
PROP_TYPE = "type"
87 changes: 87 additions & 0 deletions src/synology_dsm/api/backup/task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""HyperBackup task data."""
from typing import Any
from typing import Dict

from .const import PROP_DATA_ENCRYPTION
from .const import PROP_DATA_TYPE
from .const import PROP_NAME
from .const import PROP_SOURCE
from .const import PROP_STATE
from .const import PROP_STATUS
from .const import PROP_TARGET_ID
from .const import PROP_TARGET_TYPE
from .const import PROP_TASKID
from .const import PROP_TRANSFER_TYPE
from .const import PROP_TYPE


class SynoBackupTask:
"""Class containing HyperBackup task data."""

def __init__(self, data: Dict[str, Any]):
"""Initialize a HyperBackup task."""
self._data = data

def update(self, data: Dict[str, Any]):
"""Update the task."""
self._data = data

@property
def as_dict(self) -> Dict[str, Any]:
"""Return all details as dictionary."""
return self._data

@property
def data_enc(self) -> bool:
"""Return data encryption."""
return self._data.get(PROP_DATA_ENCRYPTION)

@property
def data_type(self) -> str:
"""Return data type."""
return self._data.get(PROP_DATA_TYPE)

@property
def name(self) -> str:
"""Return name."""
return self._data.get(PROP_NAME)

@property
def source(self) -> Dict[str, Any]:
"""Return source."""
return self._data.get(PROP_SOURCE)

@property
def state(self) -> str:
"""Return state."""
return self._data.get(PROP_STATE)

@property
def status(self) -> str:
"""Return status."""
return self._data.get(PROP_STATUS)

@property
def target_id(self) -> str:
"""Return target id."""
return self._data.get(PROP_TARGET_ID)

@property
def target_type(self) -> str:
"""Return target type."""
return self._data.get(PROP_TARGET_TYPE)

@property
def task_id(self) -> int:
"""Return task id."""
return self._data.get(PROP_TASKID)

@property
def transfer_type(self) -> str:
"""Return transfer type."""
return self._data.get(PROP_TRANSFER_TYPE)

@property
def type(self) -> str:
"""Return type."""
return self._data.get(PROP_TYPE)
18 changes: 18 additions & 0 deletions src/synology_dsm/synology_dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from requests import Session
from requests.exceptions import RequestException

from .api.backup import SynoBackup
from .api.core.security import SynoCoreSecurity
from .api.core.share import SynoCoreShare
from .api.core.system import SynoCoreSystem
Expand Down Expand Up @@ -69,6 +70,7 @@ def __init__(
self._apis = {
"SYNO.API.Info": {"maxVersion": 1, "minVersion": 1, "path": "query.cgi"}
}
self._backup = None
self._download = None
self._information = None
self._network = None
Expand Down Expand Up @@ -322,6 +324,9 @@ def _execute_request(self, method: str, url: str, params: dict, **kwargs):

def update(self, with_information: bool = False, with_network: bool = False):
"""Updates the various instanced modules."""
if self._backup:
self._backup.update()

if self._download:
self._download.update()

Expand Down Expand Up @@ -360,6 +365,9 @@ def reset(self, api: any) -> bool:
if hasattr(self, "_" + api):
setattr(self, "_" + api, None)
return True
if api == SynoBackup.API_KEY:
self._backup = None
return True
if api == SynoCoreSecurity.API_KEY:
self._security = None
return True
Expand All @@ -384,6 +392,9 @@ def reset(self, api: any) -> bool:
if api == SynoSurveillanceStation.API_KEY:
self._surveillance = None
return True
if isinstance(api, SynoBackup):
self._backup = None
return True
if isinstance(api, SynoCoreSecurity):
self._security = None
return True
Expand All @@ -410,6 +421,13 @@ def reset(self, api: any) -> bool:
return True
return False

@property
def backup(self) -> SynoBackup:
"""Gets NAS HyperBackup."""
if not self._backup:
self._backup = SynoBackup(self)
return self._backup

@property
def download_station(self) -> SynoDownloadStation:
"""Gets NAS DownloadStation."""
Expand Down
13 changes: 13 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from .api_data.dsm_6 import DSM_6_AUTH_LOGIN
from .api_data.dsm_6 import DSM_6_AUTH_LOGIN_2SA
from .api_data.dsm_6 import DSM_6_AUTH_LOGIN_2SA_OTP
from .api_data.dsm_6 import DSM_6_BACKUP_TASK_GETS
from .api_data.dsm_6 import DSM_6_BACKUP_TASK_LIST
from .api_data.dsm_6 import DSM_6_CORE_SECURITY
from .api_data.dsm_6 import DSM_6_CORE_SECURITY_UPDATE_OUTOFDATE
from .api_data.dsm_6 import DSM_6_CORE_SHARE
Expand Down Expand Up @@ -50,6 +52,7 @@
from .const import ERROR_AUTH_OTP_AUTHENTICATE_FAILED
from .const import ERROR_INSUFFICIENT_USER_PRIVILEGE
from synology_dsm import SynologyDSM
from synology_dsm.api.backup import SynoBackup
from synology_dsm.api.core.security import SynoCoreSecurity
from synology_dsm.api.core.share import SynoCoreShare
from synology_dsm.api.core.system import SynoCoreSystem
Expand Down Expand Up @@ -82,6 +85,8 @@
"AUTH_LOGIN": DSM_6_AUTH_LOGIN,
"AUTH_LOGIN_2SA": DSM_6_AUTH_LOGIN_2SA,
"AUTH_LOGIN_2SA_OTP": DSM_6_AUTH_LOGIN_2SA_OTP,
"BACKUP_TASK_LIST": DSM_6_BACKUP_TASK_LIST,
"BACKUP_TASK_GETS": DSM_6_BACKUP_TASK_GETS,
"DSM_INFORMATION": DSM_6_DSM_INFORMATION,
"DSM_NETWORK": DSM_6_DSM_NETWORK_2LAN_1PPPOE,
"CORE_SECURITY": DSM_6_CORE_SECURITY,
Expand Down Expand Up @@ -219,6 +224,12 @@ def _execute_request(self, method, url, params, **kwargs):
if not self._session_id:
return ERROR_INSUFFICIENT_USER_PRIVILEGE

if SynoBackup.API_KEY_TASK in url:
if "list" in url:
return DSM_6_BACKUP_TASK_LIST
elif "get" in url:
return DSM_6_BACKUP_TASK_GETS[params["task_id"]]

if SynoCoreSecurity.API_KEY in url:
if self.error:
return DSM_6_CORE_SECURITY_UPDATE_OUTOFDATE
Expand Down Expand Up @@ -248,9 +259,11 @@ def _execute_request(self, method, url, params, **kwargs):
return DSM_6_DOWNLOAD_STATION_INFO_INFO
if "GetConfig" in url:
return DSM_6_DOWNLOAD_STATION_INFO_CONFIG

if SynoDownloadStation.STAT_API_KEY in url:
if "GetInfo" in url:
return DSM_6_DOWNLOAD_STATION_STAT_INFO

if SynoDownloadStation.TASK_API_KEY in url:
if "List" in url:
return DSM_6_DOWNLOAD_STATION_TASK_LIST
Expand Down
4 changes: 4 additions & 0 deletions tests/api_data/dsm_6/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""DSM 6 datas."""
from .backup.const_6_backup_task import DSM_6_BACKUP_TASK_GETS
from .backup.const_6_backup_task import DSM_6_BACKUP_TASK_LIST
from .const_6_api_auth import DSM_6_AUTH_LOGIN
from .const_6_api_auth import DSM_6_AUTH_LOGIN_2SA
from .const_6_api_auth import DSM_6_AUTH_LOGIN_2SA_OTP
Expand Down Expand Up @@ -65,6 +67,8 @@
"DSM_6_AUTH_LOGIN_2SA",
"DSM_6_AUTH_LOGIN_2SA_OTP",
"DSM_6_API_INFO",
"DSM_6_BACKUP_TASK_LIST",
"DSM_6_BACKUP_TASK_GETS",
"DSM_6_CORE_SECURITY",
"DSM_6_CORE_SECURITY_UPDATE_OUTOFDATE",
"DSM_6_CORE_SHARE",
Expand Down
1 change: 1 addition & 0 deletions tests/api_data/dsm_6/backup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""DSM 6 SYNO.Backup.* datas."""
Loading