Skip to content

Commit 0622bcf

Browse files
authored
Refactor requests (#33)
* API discovery (SYNO.API.Info) + use Exceptions - remove dsm_version - use SynologyDSMRequestException for failed requests * _discover_apis any time * simplify requests - Add api.request(api, method, params=None) * Add connection failed tests * Finalized ? * Fix SynologyDSMRequestException not beeing SynologyDSMException * Fix SynologyDSMAPINotExistsException not beeing SynologyDSMException * Add Virtual Machine Manager API documentation * Can get and post request - Add error handling by API code * Pylint * Add get + post tests + SynologyDSMAPIErrorException
1 parent 6f77082 commit 0622bcf

File tree

11 files changed

+567
-224
lines changed

11 files changed

+567
-224
lines changed

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,5 @@ Official references
124124
- `File Station API documentation (2013-2019) <https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/FileStation/All/enu/Synology_File_Station_API_Guide.pdf>`_
125125

126126
- `Surveillance Station API documentation (2012-2020) <https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/SurveillanceStation/All/enu/Surveillance_Station_Web_API.pdf>`_
127+
128+
- `Virtual Machine Manager API documentation (2015-2019) <https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/Virtualization/All/enu/Synology_Virtual_Machine_Manager_API_Guide.pdf>`_

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ requests>=2.20.0
22
urllib3>=1.24.3,<1.25
33
six>=1.14.0
44
future>=0.18.2
5+
simplejson>=3.16.0

synology_dsm/api/dsm/information.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def uptime(self):
4646
"""Uptime of the NAS."""
4747
return self._data.get("uptime")
4848

49+
@property
50+
def version(self):
51+
"""Version of the NAS (build version)."""
52+
return self._data.get("version")
53+
4954
@property
5055
def version_string(self):
5156
"""Version of the NAS."""

synology_dsm/const.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# -*- coding: utf-8 -*-
2+
"""Library constants."""
3+
4+
5+
# SYNO.*
6+
ERROR_COMMON = {
7+
100: "Unknown error",
8+
101: "No parameter API, method, or version",
9+
102: "API does not exist",
10+
103: "API method does not exist",
11+
104: "API version not supported",
12+
105: "Insufficient user privilege",
13+
106: "Session timeout",
14+
107: "Session interrupted by duplicate login",
15+
114: "Missing required parameters",
16+
117: "Unknown internal error",
17+
120: "Invalid parameter",
18+
160: "Insufficient application privilege",
19+
}
20+
21+
# SYNO.API.Auth
22+
ERROR_AUTH = {
23+
400: "Invalid credentials",
24+
401: "Guest or disabled account",
25+
402: "Permission denied",
26+
403: "One time password not specified",
27+
404: "One time password authenticate failed",
28+
405: "App portal incorrect",
29+
406: "One time password code enforced",
30+
407: "Max Tries (if auto blocking is set to true)",
31+
408: "Password Expired Can not Change",
32+
409: "Password Expired",
33+
410: "Password must change (when first time use or after reset password by admin)",
34+
411: "Account Locked (when account max try exceed)",
35+
}
36+
37+
# SYNO.DownloadStation[2].BTSearch
38+
ERROR_DOWNLOAD_SEARCH = {
39+
400: "Unknown error",
40+
401: "Invalid parameter",
41+
402: "Parse the user setting failed",
42+
403: "Get category failed",
43+
404: "Get the search result from DB failed",
44+
405: "Get the user setting failed",
45+
}
46+
# SYNO.DownloadStation[2].Task
47+
ERROR_DOWNLOAD_TASK = {
48+
400: "File upload failed",
49+
401: "Max number of tasks reached",
50+
402: "Destination denied",
51+
403: "Destination does not exist",
52+
404: "Invalid task id",
53+
405: "Invalid task action",
54+
406: "No default destination",
55+
407: "Set destination failed",
56+
408: "File does not exist",
57+
}
58+
59+
# SYNO.FileStation.*
60+
ERROR_FILE = {
61+
400: "Invalid parameter of file operation",
62+
401: "Unknown error of file operation",
63+
402: "System is too busy",
64+
403: "Invalid user does this file operation",
65+
404: "Invalid group does this file operation",
66+
405: "Invalid user and group does this file operation",
67+
406: "Can’t get user/group information from the account server Operation not permitted",
68+
407: "Operation not permitted",
69+
408: "No such file or directory",
70+
409: "Non-supported file system",
71+
410: "Failed to connect internet-based file system (ex: CIFS)",
72+
411: "Read-only file system",
73+
412: "Filename too long in the non-encrypted file system",
74+
413: "Filename too long in the encrypted file system",
75+
414: "File already exists",
76+
415: "Disk quota exceeded",
77+
416: "No space left on device",
78+
417: "Input/output error",
79+
418: "Illegal name or path",
80+
419: "Illegal file name",
81+
420: "Illegal file name on FAT file system",
82+
421: "Device or resource busy",
83+
599: "No such task of the file operation",
84+
900: "Failed to delete file(s)/folder(s). More information in <errors> object",
85+
1000: "Failed to copy files/folders. More information in <errors> object",
86+
1001: "Failed to move files/folders. More information in <errors> object",
87+
1002: "An error occurred at the destination. More information in <errors> object",
88+
1003: "Cannot overwrite or skip the existing file because no overwrite parameter is given",
89+
1004: "File cannot overwrite a folder with the same name, or folder cannot overwrite a file with the same name",
90+
1006: "Cannot copy/move file/folder with special characters to a FAT32 file system",
91+
1007: "Cannot copy/move a file bigger than 4G to a FAT32 file system",
92+
1100: "Failed to create a folder. More information in <errors> object",
93+
1101: "The number of folders to the parent folder would exceed the system limitation",
94+
1300: "Failed to compress files/folders",
95+
1301: "Cannot create the archive because the given archive name is too long",
96+
1400: "Failed to extract files",
97+
1401: "Cannot open the file as archive",
98+
1402: "Failed to read archive data error",
99+
1403: "Wrong archive password",
100+
1404: "Failed to get the file and dir list in an archive",
101+
1405: "Failed to find the item ID in an archive file",
102+
1200: "Failed to rename it. More information in <errors> object",
103+
1800: "There is no Content-Length information in the HTTP header or the received size doesn’t match the value of Content-Length information in the HTTP header",
104+
1801: "Wait too long, no date can be received from client (Default maximum wait time is 3600 seconds)",
105+
1802: "No filename information in the last part of file content",
106+
1803: "Upload connection is cancelled",
107+
1804: "Failed to upload too big file to FAT file system",
108+
1805: "Can’t overwrite or skip the existed file, if no overwrite parameter is given",
109+
2000: "Sharing link does not exist",
110+
2001: "Cannot generate sharing link because too many sharing links exist",
111+
2002: "Failed to access sharing links",
112+
}
113+
114+
# SYNO.SurveillanceStation.*
115+
ERROR_SURVEILLANCE = {
116+
400: "Execution failed",
117+
401: "Invalid parameter",
118+
402: "Camera disabled",
119+
403: "Insufficient license",
120+
404: "Codec activation failed",
121+
405: "CMS server connection failed",
122+
407: "CMS closed",
123+
412: "Need to add license",
124+
413: "Reach the maximum of platform",
125+
414: "Some events not exist",
126+
415: "Message connect failed",
127+
417: "Test connection error",
128+
418: "Object/VisualStation ID does not exist",
129+
419: "VisualStation name repetition",
130+
439: "Too many items selected",
131+
446: "Task path already exist",
132+
522: "Original task is migrating",
133+
534: "Exceed name length limitation",
134+
}
135+
136+
# SYNO.Virtualization.*
137+
ERROR_VIRTUALIZATION = {
138+
400: "Unknown error",
139+
401: "Bad parameter",
140+
402: "Operation failed",
141+
403: "Name conflict",
142+
404: "The number of iSCSI LUNs has reached the system limit",
143+
500: "Note: vdisk is based on iSCSI LUN, which is also limited by the system",
144+
501: "The cluster is frozen. More than half of the hosts are offline",
145+
600: "The cluster is in the incompatible mode. Please upgrade to a compatible DSM version and try again",
146+
601: "The cluster is not ready",
147+
700: "The host is offline",
148+
900: "The storage is in invalid",
149+
901: "Failed to set a host to a virtual machine",
150+
902: "The virtual machine does not have a host",
151+
903: "Failed to power on a virtual machine due to insufficient CPU threads",
152+
904: "Failed to power on a virtual machine due to insufficient memory",
153+
905: "The status of virtual machine is online",
154+
906: "MAC conflict",
155+
907: "Failed to create virtual machine because the selected image is not found",
156+
908: "The status of virtual machine is offline",
157+
909: "Failed to power on a virtual machine due to insufficient CPU threads for reservation on the host",
158+
910: "Failed to power on the virtual machine because there is no corresponding networking on the host",
159+
911: "Only the VirtIO hard disk controller can be used to boot the virtual machine remotely. Virtual machines with UEFI enabled cannot be powered on remotely",
160+
1000: "Cannot find task_id",
161+
1001: "Need Virtual Machine Manager Pro",
162+
1400: "The result of image creating is partial success",
163+
1600: "The virtual machine has been successfully edited. However, errors occurred while reserving the memory or CPU on the HA hosts",
164+
}

synology_dsm/exceptions.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,51 @@
11
# -*- coding: utf-8 -*-
22
"""Library exceptions."""
3-
3+
from .const import ERROR_AUTH, ERROR_COMMON, ERROR_DOWNLOAD_SEARCH, ERROR_DOWNLOAD_TASK, ERROR_FILE, ERROR_SURVEILLANCE, ERROR_VIRTUALIZATION
44

55
class SynologyDSMException(Exception):
66
"""Generic Synology DSM exception."""
77
pass
88

9+
# Request
10+
class SynologyDSMRequestException(SynologyDSMException):
11+
"""Request exception."""
12+
def __init__(self, exception):
13+
ex_class = exception.__class__.__name__
14+
ex_reason = exception.args[0]
15+
if hasattr(exception.args[0], "reason"):
16+
ex_reason = exception.args[0].reason
17+
message = "%s = %s" % (ex_class, ex_reason)
18+
super(SynologyDSMRequestException, self).__init__(message)
19+
20+
# API
21+
class SynologyDSMAPINotExistsException(SynologyDSMException):
22+
"""API not exists exception."""
23+
def __init__(self, api):
24+
message = "API %s does not exists" % api
25+
super(SynologyDSMAPINotExistsException, self).__init__(message)
26+
27+
class SynologyDSMAPIErrorException(SynologyDSMException):
28+
"""API returns an error exception."""
29+
def __init__(self, api, code):
30+
reason = ERROR_COMMON.get(code)
31+
if api and not reason:
32+
if api == "SYNO.API.Auth":
33+
reason = ERROR_AUTH.get(code)
34+
elif "SYNO.DownloadStation" in api:
35+
if "BTSearch" in api:
36+
reason = ERROR_DOWNLOAD_SEARCH.get(code)
37+
elif "Task" in api:
38+
reason = ERROR_DOWNLOAD_TASK.get(code)
39+
elif "SYNO.FileStation" in api:
40+
reason = ERROR_FILE.get(code)
41+
elif "SYNO.SurveillanceStation" in api:
42+
reason = ERROR_SURVEILLANCE.get(code)
43+
elif "SYNO.Virtualization" in api:
44+
reason = ERROR_VIRTUALIZATION.get(code)
45+
if not reason:
46+
reason = "Unknown"
47+
message = "\n Code: %s\n Reason: %s" % (str(code), reason)
48+
super(SynologyDSMAPIErrorException, self).__init__(message)
949

1050
# Login
1151
class SynologyDSMLoginFailedException(SynologyDSMException):

0 commit comments

Comments
 (0)