calagoapi 1.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- calagoapi/__init__.py +190 -0
- calagoapi/account/__init__.py +14 -0
- calagoapi/account/account.py +292 -0
- calagoapi/account/auth.py +72 -0
- calagoapi/account/models.py +221 -0
- calagoapi/admin/__init__.py +48 -0
- calagoapi/admin/admin.py +341 -0
- calagoapi/admin/managers.py +490 -0
- calagoapi/admin/resources.py +970 -0
- calagoapi/aio/__init__.py +9 -0
- calagoapi/aio/console.py +289 -0
- calagoapi/aio/panel.py +176 -0
- calagoapi/api/__init__.py +63 -0
- calagoapi/api/account.py +195 -0
- calagoapi/api/admin.py +402 -0
- calagoapi/api/attachments.py +27 -0
- calagoapi/api/auth.py +52 -0
- calagoapi/api/backups.py +99 -0
- calagoapi/api/client.py +198 -0
- calagoapi/api/databases.py +217 -0
- calagoapi/api/files.py +210 -0
- calagoapi/api/network.py +84 -0
- calagoapi/api/public.py +13 -0
- calagoapi/api/schedules.py +79 -0
- calagoapi/api/servers.py +114 -0
- calagoapi/api/users.py +27 -0
- calagoapi/api/versions.py +29 -0
- calagoapi/backups/__init__.py +8 -0
- calagoapi/backups/backup.py +292 -0
- calagoapi/backups/manager.py +177 -0
- calagoapi/console/__init__.py +6 -0
- calagoapi/console/console.py +392 -0
- calagoapi/databases/__init__.py +12 -0
- calagoapi/databases/database.py +445 -0
- calagoapi/databases/explorer.py +159 -0
- calagoapi/databases/manager.py +122 -0
- calagoapi/files/__init__.py +9 -0
- calagoapi/files/file.py +196 -0
- calagoapi/files/manager.py +437 -0
- calagoapi/network/__init__.py +8 -0
- calagoapi/network/allocation.py +99 -0
- calagoapi/network/manager.py +132 -0
- calagoapi/nodes/__init__.py +6 -0
- calagoapi/nodes/node.py +477 -0
- calagoapi/panel.py +162 -0
- calagoapi/schedules/__init__.py +14 -0
- calagoapi/schedules/builders.py +461 -0
- calagoapi/schedules/manager.py +107 -0
- calagoapi/schedules/schedule.py +214 -0
- calagoapi/servers/__init__.py +13 -0
- calagoapi/servers/admin.py +430 -0
- calagoapi/servers/generic.py +785 -0
- calagoapi/servers/manager.py +167 -0
- calagoapi/servers/minecraft.py +207 -0
- calagoapi/tunnels/__init__.py +5 -0
- calagoapi/tunnels/tunnel.py +112 -0
- calagoapi/users/__init__.py +11 -0
- calagoapi/users/activity.py +45 -0
- calagoapi/users/subuser.py +127 -0
- calagoapi/users/user.py +267 -0
- calagoapi/utils/__init__.py +43 -0
- calagoapi/utils/convert.py +113 -0
- calagoapi/utils/exceptions.py +72 -0
- calagoapi/utils/model.py +142 -0
- calagoapi/utils/resource.py +100 -0
- calagoapi/utils/time.py +68 -0
- calagoapi-1.0.dev1.dist-info/METADATA +266 -0
- calagoapi-1.0.dev1.dist-info/RECORD +71 -0
- calagoapi-1.0.dev1.dist-info/WHEEL +5 -0
- calagoapi-1.0.dev1.dist-info/licenses/LICENSE +674 -0
- calagoapi-1.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from calagoapi.utils.model import Model, idOf
|
|
4
|
+
from calagoapi.utils.convert import formatBytes
|
|
5
|
+
from calagoapi.utils.exceptions import WaitTimeoutError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Backup(Model):
|
|
9
|
+
'''
|
|
10
|
+
A server backup.
|
|
11
|
+
|
|
12
|
+
Returned by `server.createBackup()`, `server.backups.getBackups()` and friends.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
server: The server the backup belongs to.
|
|
16
|
+
data: Raw backup data from Calagopus.
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
backup = server.createBackup('before-update')
|
|
20
|
+
backup.waitUntilComplete()
|
|
21
|
+
if backup.isSuccessful():
|
|
22
|
+
print(backup.getName(), backup.getSize(formatted=True))
|
|
23
|
+
'''
|
|
24
|
+
def __init__(self, server, data: dict):
|
|
25
|
+
super().__init__(server.panel, data)
|
|
26
|
+
self.server = server
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def backup_id(self):
|
|
30
|
+
return self.getUUID()
|
|
31
|
+
|
|
32
|
+
# getters
|
|
33
|
+
def getName(self) -> str:
|
|
34
|
+
'''Returns the backup name.'''
|
|
35
|
+
return self.data.get('name')
|
|
36
|
+
|
|
37
|
+
def getSize(self, formatted: bool = False):
|
|
38
|
+
'''
|
|
39
|
+
Returns the backup size in bytes.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
formatted: Return a human readable string like "1.2 GiB" instead.
|
|
43
|
+
'''
|
|
44
|
+
size = self.data.get('bytes')
|
|
45
|
+
return formatBytes(size) if formatted else size
|
|
46
|
+
|
|
47
|
+
def getFileCount(self) -> int:
|
|
48
|
+
'''Returns how many files the backup contains.'''
|
|
49
|
+
return self.data.get('files')
|
|
50
|
+
|
|
51
|
+
def getChecksum(self) -> str:
|
|
52
|
+
'''Returns the backup checksum, once completed.'''
|
|
53
|
+
return self.data.get('checksum')
|
|
54
|
+
|
|
55
|
+
def getKind(self) -> str:
|
|
56
|
+
'''Returns "server" for file backups or "database_instance" for database backups.'''
|
|
57
|
+
return self.data.get('kind')
|
|
58
|
+
|
|
59
|
+
def getDatabaseType(self) -> str:
|
|
60
|
+
'''Returns the database type for database backups, otherwise None.'''
|
|
61
|
+
return self.data.get('database_type')
|
|
62
|
+
|
|
63
|
+
def getGroupId(self) -> str:
|
|
64
|
+
'''Returns the UUID of the backup group this backup is in, or None.'''
|
|
65
|
+
return self.data.get('backup_group_uuid')
|
|
66
|
+
|
|
67
|
+
def getIgnoredFiles(self) -> list:
|
|
68
|
+
'''Returns the ignore patterns used when creating the backup.'''
|
|
69
|
+
return self.data.get('ignored_files', [])
|
|
70
|
+
|
|
71
|
+
def getCompleted(self) -> str:
|
|
72
|
+
'''Returns when the backup finished, or None while it is running.'''
|
|
73
|
+
return self.data.get('completed')
|
|
74
|
+
|
|
75
|
+
def getStatus(self) -> str:
|
|
76
|
+
'''
|
|
77
|
+
Returns the backup status.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
'in_progress', 'successful' or 'failed'.
|
|
81
|
+
'''
|
|
82
|
+
if not self.data.get('completed'):
|
|
83
|
+
return 'in_progress'
|
|
84
|
+
return 'successful' if self.data.get('is_successful') else 'failed'
|
|
85
|
+
|
|
86
|
+
# state checks
|
|
87
|
+
def isCompleted(self) -> bool:
|
|
88
|
+
'''Returns True once the backup has finished (successfully or not).'''
|
|
89
|
+
return self.getStatus() != 'in_progress'
|
|
90
|
+
|
|
91
|
+
def isInProgress(self) -> bool:
|
|
92
|
+
'''Returns True while the backup is still being created.'''
|
|
93
|
+
return self.getStatus() == 'in_progress'
|
|
94
|
+
|
|
95
|
+
def isSuccessful(self) -> bool:
|
|
96
|
+
'''Returns True if the backup completed successfully.'''
|
|
97
|
+
return self.getStatus() == 'successful'
|
|
98
|
+
|
|
99
|
+
def isFailed(self) -> bool:
|
|
100
|
+
'''Returns True if the backup completed but failed.'''
|
|
101
|
+
return self.getStatus() == 'failed'
|
|
102
|
+
|
|
103
|
+
def isLocked(self) -> bool:
|
|
104
|
+
'''Returns True if the backup is locked against deletion.'''
|
|
105
|
+
return bool(self.data.get('is_locked'))
|
|
106
|
+
|
|
107
|
+
def isBrowsable(self) -> bool:
|
|
108
|
+
'''Returns True if the backup contents can be browsed.'''
|
|
109
|
+
return bool(self.data.get('is_browsable'))
|
|
110
|
+
|
|
111
|
+
def isStreaming(self) -> bool:
|
|
112
|
+
'''Returns True if the backup can be streamed during download.'''
|
|
113
|
+
return bool(self.data.get('is_streaming'))
|
|
114
|
+
|
|
115
|
+
# actions
|
|
116
|
+
def refresh(self) -> 'Backup':
|
|
117
|
+
'''Re-fetches the backup from the panel.'''
|
|
118
|
+
self.data = self.panel.api.backups.get(self.server.server_id, self.backup_id)
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
def waitUntilComplete(self, timeout: int = 3600, interval: int = 5) -> 'Backup':
|
|
122
|
+
'''
|
|
123
|
+
Blocks until the backup finishes.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
timeout: Maximum seconds to wait.
|
|
127
|
+
interval: Seconds between checks.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
WaitTimeoutError: The backup did not finish in time.
|
|
131
|
+
'''
|
|
132
|
+
deadline = time.monotonic() + timeout
|
|
133
|
+
while self.refresh().isInProgress():
|
|
134
|
+
if time.monotonic() >= deadline:
|
|
135
|
+
raise WaitTimeoutError(f'Backup {self.getName()!r} did not finish within {timeout}s')
|
|
136
|
+
time.sleep(interval)
|
|
137
|
+
return self
|
|
138
|
+
|
|
139
|
+
def restore(self, truncate_directory: bool = False, restore_startup: bool = None, database_instance=None) -> None:
|
|
140
|
+
'''
|
|
141
|
+
Restores the server from this backup.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
truncate_directory: Delete all current files before restoring.
|
|
145
|
+
restore_startup: Also restore the startup command and variables.
|
|
146
|
+
database_instance: For database backups, the instance to restore into.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
backup.restore(truncate_directory=True)
|
|
150
|
+
'''
|
|
151
|
+
return self.panel.api.backups.restore(
|
|
152
|
+
self.server.server_id, self.backup_id, truncate_directory, restore_startup, idOf(database_instance)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def rename(self, name: str) -> 'Backup':
|
|
156
|
+
'''Renames the backup.'''
|
|
157
|
+
self.panel.api.backups.update(self.server.server_id, self.backup_id, name=name)
|
|
158
|
+
return self._update({'name': name})
|
|
159
|
+
|
|
160
|
+
def setName(self, name: str) -> 'Backup':
|
|
161
|
+
'''Alias of rename().'''
|
|
162
|
+
return self.rename(name)
|
|
163
|
+
|
|
164
|
+
def lock(self) -> 'Backup':
|
|
165
|
+
'''Locks the backup so it cannot be deleted.'''
|
|
166
|
+
self.panel.api.backups.update(self.server.server_id, self.backup_id, locked=True)
|
|
167
|
+
return self._update({'is_locked': True})
|
|
168
|
+
|
|
169
|
+
def unlock(self) -> 'Backup':
|
|
170
|
+
'''Unlocks the backup.'''
|
|
171
|
+
self.panel.api.backups.update(self.server.server_id, self.backup_id, locked=False)
|
|
172
|
+
return self._update({'is_locked': False})
|
|
173
|
+
|
|
174
|
+
def moveToGroup(self, group) -> 'Backup':
|
|
175
|
+
'''
|
|
176
|
+
Moves the backup into a backup group.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
group: A BackupGroup or group UUID.
|
|
180
|
+
'''
|
|
181
|
+
group_id = idOf(group)
|
|
182
|
+
self.panel.api.backups.update(self.server.server_id, self.backup_id, backup_group_uuid=group_id)
|
|
183
|
+
return self._update({'backup_group_uuid': group_id})
|
|
184
|
+
|
|
185
|
+
def getDownloadUrl(self, archive_format: str = None) -> str:
|
|
186
|
+
'''
|
|
187
|
+
Returns a signed, temporary download URL.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
archive_format: Optional archive format, e.g. 'tar_gz' or 'zip'.
|
|
191
|
+
'''
|
|
192
|
+
return self.panel.api.backups.downloadUrl(self.server.server_id, self.backup_id, archive_format)
|
|
193
|
+
|
|
194
|
+
def download(self, destination: str = None, archive_format: str = None):
|
|
195
|
+
'''
|
|
196
|
+
Downloads the backup.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
destination: Local file to save to. If omitted the bytes are returned.
|
|
200
|
+
archive_format: Optional archive format.
|
|
201
|
+
|
|
202
|
+
Example:
|
|
203
|
+
backup.download('backup.tar.gz')
|
|
204
|
+
'''
|
|
205
|
+
r = self.panel.api.files.fetch(self.getDownloadUrl(archive_format), stream=destination is not None)
|
|
206
|
+
if destination is None:
|
|
207
|
+
return r.content
|
|
208
|
+
with open(destination, 'wb') as f:
|
|
209
|
+
for chunk in r.iter_content(chunk_size=1024 * 1024):
|
|
210
|
+
f.write(chunk)
|
|
211
|
+
return destination
|
|
212
|
+
|
|
213
|
+
def exportToServer(self, path: str, archive_format: str = None, foreground: bool = None):
|
|
214
|
+
'''
|
|
215
|
+
Writes the backup as an archive into the server's own file system.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
path: Destination path on the server, e.g. "/exports/backup.tar.gz".
|
|
219
|
+
'''
|
|
220
|
+
return self.panel.api.backups.export(self.server.server_id, self.backup_id, path, archive_format, foreground)
|
|
221
|
+
|
|
222
|
+
def getArchiveInfo(self) -> dict:
|
|
223
|
+
'''Returns the archive format and size the panel would serve for download.'''
|
|
224
|
+
return self.panel.api.backups.query(self.server.server_id, self.backup_id)
|
|
225
|
+
|
|
226
|
+
def delete(self) -> None:
|
|
227
|
+
'''Deletes the backup.'''
|
|
228
|
+
return self.panel.api.backups.delete(self.server.server_id, self.backup_id)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class BackupGroup(Model):
|
|
232
|
+
'''
|
|
233
|
+
A named group of backups with its own retention policy.
|
|
234
|
+
|
|
235
|
+
Example:
|
|
236
|
+
group = server.backups.createBackupGroup('daily', retention={'daily': 7})
|
|
237
|
+
backup = server.createBackup('nightly', group=group)
|
|
238
|
+
'''
|
|
239
|
+
def __init__(self, server, data: dict):
|
|
240
|
+
super().__init__(server.panel, data)
|
|
241
|
+
self.server = server
|
|
242
|
+
|
|
243
|
+
def getName(self) -> str:
|
|
244
|
+
'''Returns the group name.'''
|
|
245
|
+
return self.data.get('name')
|
|
246
|
+
|
|
247
|
+
def getOrder(self) -> int:
|
|
248
|
+
'''Returns the display order.'''
|
|
249
|
+
return self.data.get('order')
|
|
250
|
+
|
|
251
|
+
def getRetention(self) -> dict:
|
|
252
|
+
'''Returns the retention policy (count, days, daily, weekly, monthly, yearly).'''
|
|
253
|
+
return self.data.get('retention', {})
|
|
254
|
+
|
|
255
|
+
def getTotalBackups(self) -> int:
|
|
256
|
+
'''Returns the number of backups in the group.'''
|
|
257
|
+
return self.data.get('total_backups')
|
|
258
|
+
|
|
259
|
+
def getUsableBackups(self) -> int:
|
|
260
|
+
'''Returns the number of successful backups in the group.'''
|
|
261
|
+
return self.data.get('usable_backups')
|
|
262
|
+
|
|
263
|
+
def getBackups(self, search: str = None, page: int = None, per_page: int = None):
|
|
264
|
+
'''Returns the backups in this group.'''
|
|
265
|
+
return self.panel.api.backups.groupBackups(
|
|
266
|
+
self.server.server_id, self.getUUID(), search, page, per_page
|
|
267
|
+
).map(lambda data: Backup(self.server, data))
|
|
268
|
+
|
|
269
|
+
def rename(self, name: str) -> 'BackupGroup':
|
|
270
|
+
'''Renames the group.'''
|
|
271
|
+
self.panel.api.backups.updateGroup(self.server.server_id, self.getUUID(), name=name)
|
|
272
|
+
return self._update({'name': name})
|
|
273
|
+
|
|
274
|
+
def setRetention(self, count: int = 0, days: int = 0, daily: int = 0, weekly: int = 0, monthly: int = 0, yearly: int = 0) -> 'BackupGroup':
|
|
275
|
+
'''
|
|
276
|
+
Sets how many backups the group keeps. 0 means unlimited.
|
|
277
|
+
|
|
278
|
+
Example:
|
|
279
|
+
group.setRetention(daily=7, weekly=4)
|
|
280
|
+
'''
|
|
281
|
+
retention = {'count': count, 'days': days, 'daily': daily, 'weekly': weekly, 'monthly': monthly, 'yearly': yearly}
|
|
282
|
+
self.panel.api.backups.updateGroup(self.server.server_id, self.getUUID(), retention=retention)
|
|
283
|
+
return self._update({'retention': retention})
|
|
284
|
+
|
|
285
|
+
def delete(self, lock_backups: bool = None) -> None:
|
|
286
|
+
'''
|
|
287
|
+
Deletes the group.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
lock_backups: Lock the group's backups so they survive without a retention policy.
|
|
291
|
+
'''
|
|
292
|
+
return self.panel.api.backups.deleteGroup(self.server.server_id, self.getUUID(), lock_backups)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from calagoapi.backups.backup import Backup, BackupGroup
|
|
2
|
+
from calagoapi.utils.model import idOf
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BackupManager:
|
|
6
|
+
'''
|
|
7
|
+
Backup management for one server, available as `server.backups`.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
server: The server to manage backups for.
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
backup = server.backups.createBackup('pre-update')
|
|
14
|
+
for backup in server.backups.getBackups():
|
|
15
|
+
print(backup.getName(), backup.getStatus())
|
|
16
|
+
'''
|
|
17
|
+
def __init__(self, server):
|
|
18
|
+
self.server = server
|
|
19
|
+
self.api = server.panel.api.backups
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def server_id(self):
|
|
23
|
+
return self.server.server_id
|
|
24
|
+
|
|
25
|
+
def _wrap(self, data):
|
|
26
|
+
return Backup(self.server, data)
|
|
27
|
+
|
|
28
|
+
# backups
|
|
29
|
+
def getBackups(self, search: str = None, kind: str = None, ungrouped: bool = None, page: int = None, per_page: int = None):
|
|
30
|
+
'''
|
|
31
|
+
Lists the server's backups.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
search: Filter by name.
|
|
35
|
+
kind: 'server' for file backups or 'database_instance' for database backups.
|
|
36
|
+
ungrouped: Only backups that are not in a backup group.
|
|
37
|
+
page: Only fetch this page. By default every backup is returned.
|
|
38
|
+
per_page: Page size.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
A Page (list) of Backup objects.
|
|
42
|
+
'''
|
|
43
|
+
return self.api.list(self.server_id, search, ungrouped, kind, page=page, per_page=per_page).map(self._wrap)
|
|
44
|
+
|
|
45
|
+
def getSystemBackups(self, search: str = None, page: int = None, per_page: int = None):
|
|
46
|
+
'''Lists backups made by panel-wide backup policies rather than by the server's users.'''
|
|
47
|
+
return self.api.system(self.server_id, search, page, per_page).map(self._wrap)
|
|
48
|
+
|
|
49
|
+
def getBackup(self, backup_id: str) -> Backup:
|
|
50
|
+
'''
|
|
51
|
+
Returns a single backup.
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
backup = server.backups.getBackup('5f0c...')
|
|
55
|
+
'''
|
|
56
|
+
return self._wrap(self.api.get(self.server_id, backup_id))
|
|
57
|
+
|
|
58
|
+
def getLatestBackup(self, successful_only: bool = True) -> Backup:
|
|
59
|
+
'''
|
|
60
|
+
Returns the most recent backup, or None.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
successful_only: Skip backups that failed or are still running.
|
|
64
|
+
'''
|
|
65
|
+
backups = [b for b in self.getBackups() if b.isSuccessful() or not successful_only]
|
|
66
|
+
return max(backups, key=lambda b: b.getCreated() or '', default=None)
|
|
67
|
+
|
|
68
|
+
def createBackup(self, name: str = None, ignored_files: list = None, group=None, database_instance=None) -> Backup:
|
|
69
|
+
'''
|
|
70
|
+
Starts a new backup.
|
|
71
|
+
|
|
72
|
+
The backup runs in the background, use `backup.waitUntilComplete()` to wait for it.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
name: Backup name. Calagopus generates one when omitted.
|
|
76
|
+
ignored_files: Extra ignore patterns, e.g. ['logs/*', '*.tmp'].
|
|
77
|
+
group: BackupGroup or group UUID to put the backup in.
|
|
78
|
+
database_instance: Back up a database instance instead of the server files.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
The new Backup.
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
backup = server.backups.createBackup('before-update', ignored_files=['logs'])
|
|
85
|
+
'''
|
|
86
|
+
return self._wrap(self.api.create(self.server_id, name, ignored_files, idOf(group), idOf(database_instance)))
|
|
87
|
+
|
|
88
|
+
def deleteBackup(self, backup_id: str) -> None:
|
|
89
|
+
'''Deletes a backup.'''
|
|
90
|
+
return self.api.delete(self.server_id, idOf(backup_id))
|
|
91
|
+
|
|
92
|
+
def deleteBackups(self, backup_ids: list) -> dict:
|
|
93
|
+
'''
|
|
94
|
+
Deletes several backups at once.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
dict with how many were queued and skipped.
|
|
98
|
+
'''
|
|
99
|
+
return self.api.deleteMany(self.server_id, [idOf(b) for b in backup_ids])
|
|
100
|
+
|
|
101
|
+
def lockBackups(self, backup_ids: list) -> dict:
|
|
102
|
+
'''Locks several backups at once.'''
|
|
103
|
+
return self.api.updateMany(self.server_id, [idOf(b) for b in backup_ids], locked=True)
|
|
104
|
+
|
|
105
|
+
def unlockBackups(self, backup_ids: list) -> dict:
|
|
106
|
+
'''Unlocks several backups at once.'''
|
|
107
|
+
return self.api.updateMany(self.server_id, [idOf(b) for b in backup_ids], locked=False)
|
|
108
|
+
|
|
109
|
+
def moveBackups(self, backup_ids: list, group) -> dict:
|
|
110
|
+
'''Moves several backups into a backup group.'''
|
|
111
|
+
return self.api.updateMany(self.server_id, [idOf(b) for b in backup_ids], backup_group_uuid=idOf(group))
|
|
112
|
+
|
|
113
|
+
def restoreBackup(self, backup_id: str, truncate_directory: bool = False, restore_startup: bool = None) -> None:
|
|
114
|
+
'''
|
|
115
|
+
Restores the server from a backup.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
backup_id: Backup to restore.
|
|
119
|
+
truncate_directory: Delete all current files first.
|
|
120
|
+
restore_startup: Also restore the startup command and variables.
|
|
121
|
+
'''
|
|
122
|
+
return self.api.restore(self.server_id, idOf(backup_id), truncate_directory, restore_startup)
|
|
123
|
+
|
|
124
|
+
def downloadBackup(self, backup_id: str, destination: str = None, archive_format: str = None):
|
|
125
|
+
'''
|
|
126
|
+
Downloads a backup.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
destination: Local path to save to. If omitted the bytes are returned.
|
|
130
|
+
archive_format: Optional archive format.
|
|
131
|
+
'''
|
|
132
|
+
return Backup(self.server, {'uuid': idOf(backup_id)}).download(destination, archive_format)
|
|
133
|
+
|
|
134
|
+
def getDownloadUrl(self, backup_id: str, archive_format: str = None) -> str:
|
|
135
|
+
'''Returns a signed, temporary download URL for a backup.'''
|
|
136
|
+
return self.api.downloadUrl(self.server_id, idOf(backup_id), archive_format)
|
|
137
|
+
|
|
138
|
+
def getUsage(self) -> dict:
|
|
139
|
+
'''Returns how much backup storage and how many backup slots are in use.'''
|
|
140
|
+
return self.api.usage(self.server_id)
|
|
141
|
+
|
|
142
|
+
def unlockRestore(self) -> None:
|
|
143
|
+
'''Clears a stuck backup-restore lock on the server.'''
|
|
144
|
+
return self.api.unlock(self.server_id)
|
|
145
|
+
|
|
146
|
+
# groups
|
|
147
|
+
def getBackupGroups(self) -> list:
|
|
148
|
+
'''Returns the server's backup groups.'''
|
|
149
|
+
return [BackupGroup(self.server, data) for data in self.api.groups(self.server_id)]
|
|
150
|
+
|
|
151
|
+
def getBackupGroup(self, group_id_or_name: str) -> BackupGroup:
|
|
152
|
+
'''Returns a backup group by UUID or name, or None.'''
|
|
153
|
+
for group in self.getBackupGroups():
|
|
154
|
+
if group_id_or_name in (group.getUUID(), group.getName()):
|
|
155
|
+
return group
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def createBackupGroup(self, name: str, retention: dict = None) -> BackupGroup:
|
|
159
|
+
'''
|
|
160
|
+
Creates a backup group.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
name: Group name.
|
|
164
|
+
retention: Optional retention policy with keys count, days, daily, weekly, monthly, yearly.
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
server.backups.createBackupGroup('weekly', retention={'weekly': 4})
|
|
168
|
+
'''
|
|
169
|
+
return BackupGroup(self.server, self.api.createGroup(self.server_id, name, retention))
|
|
170
|
+
|
|
171
|
+
def deleteBackupGroup(self, group, lock_backups: bool = None) -> None:
|
|
172
|
+
'''Deletes a backup group.'''
|
|
173
|
+
return self.api.deleteGroup(self.server_id, idOf(group), lock_backups)
|
|
174
|
+
|
|
175
|
+
def orderBackupGroups(self, groups: list) -> None:
|
|
176
|
+
'''Sets the display order of backup groups.'''
|
|
177
|
+
return self.api.orderGroups(self.server_id, [idOf(g) for g in groups])
|