Skip to content

Commit 7112d6a

Browse files
committed
Add hot backup API, schema parameter to create_collection, and minor doc edits
1 parent e6f1ef2 commit 7112d6a

33 files changed

+1172
-415
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ python:
88
services:
99
- docker
1010
before_install:
11-
- docker create --name arango -p 8529:8529 -e ARANGO_ROOT_PASSWORD=passwd arangodb/arangodb-preview:3.7.1-rc.1 --server.jwt-secret-keyfile=/tmp/keyfile
11+
- docker create --name arango -p 8529:8529 -e ARANGO_ROOT_PASSWORD=passwd -e ARANGO_LICENSE_KEY=EVALUATION:125f16ada6047bd17eeeefa3f011070510b5fbd9d85122afdeca72c380e7ac83 arangodb/enterprise-preview:3.7.1-rc.1 --server.jwt-secret-keyfile=/tmp/keyfile
1212
- docker cp tests/static/service.zip arango:/tmp/service.zip
1313
- docker cp tests/static/keyfile arango:/tmp/keyfile
1414
- docker start arango

arango/api.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def db_name(self):
3030
"""Return the name of the current database.
3131
3232
:return: Database name.
33-
:rtype: str | unicode
33+
:rtype: str
3434
"""
3535
return self._conn.db_name
3636

@@ -39,7 +39,7 @@ def username(self):
3939
"""Return the username.
4040
4141
:returns: Username.
42-
:rtype: str | unicode
42+
:rtype: str
4343
"""
4444
return self._conn.username
4545

@@ -49,7 +49,7 @@ def context(self):
4949
5050
:return: API execution context. Possible values are "default", "async",
5151
"batch" and "transaction".
52-
:rtype: str | unicode
52+
:rtype: str
5353
"""
5454
return self._executor.context
5555

@@ -61,6 +61,6 @@ def _execute(self, request, response_handler):
6161
:param response_handler: HTTP response handler.
6262
:type response_handler: callable
6363
:return: API execution result.
64-
:rtype: str | unicode | bool | int | list | dict
64+
:rtype: str | bool | int | list | dict
6565
"""
6666
return self._executor.execute(request, response_handler)

arango/aql.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def explain(self, query, all_plans=False, max_plans=None, opt_rules=None):
5757
"""Inspect the query and return its metadata without executing it.
5858
5959
:param query: Query to inspect.
60-
:type query: str | unicode
60+
:type query: str
6161
:param all_plans: If set to True, all possible execution plans are
6262
returned in the result. If set to False, only the optimal plan
6363
is returned.
@@ -96,7 +96,7 @@ def validate(self, query):
9696
"""Parse and validate the query without executing it.
9797
9898
:param query: Query to validate.
99-
:type query: str | unicode
99+
:type query: str
100100
:return: Query details.
101101
:rtype: dict
102102
:raise arango.exceptions.AQLQueryValidateError: If validation fails.
@@ -145,7 +145,7 @@ def execute(self,
145145
"""Execute the query and return the result cursor.
146146
147147
:param query: Query to execute.
148-
:type query: str | unicode
148+
:type query: str
149149
:param count: If set to True, the total document count is included in
150150
the result cursor.
151151
:type count: bool
@@ -165,7 +165,7 @@ def execute(self,
165165
:param max_plans: Max number of plans the optimizer generates.
166166
:type max_plans: int
167167
:param optimizer_rules: List of optimizer rules.
168-
:type optimizer_rules: [str | unicode]
168+
:type optimizer_rules: [str]
169169
:param cache: If set to True, the query cache is used. The operation
170170
mode of the query cache must be set to "on" or "demand".
171171
:type cache: bool
@@ -200,10 +200,10 @@ def execute(self,
200200
:type satellite_sync_wait: int | float
201201
:param read_collections: Names of collections read during query
202202
execution. This parameter is deprecated.
203-
:type read_collections: [str | unicode]
203+
:type read_collections: [str]
204204
:param write_collections: Names of collections written to during query
205205
execution. This parameter is deprecated.
206-
:type write_collections: [str | unicode]
206+
:type write_collections: [str]
207207
:param stream: If set to True, query is executed in streaming fashion:
208208
query result is not stored server-side but calculated on the fly.
209209
Note: long-running queries hold collection locks for as long as the
@@ -296,7 +296,7 @@ def kill(self, query_id):
296296
"""Kill a running query.
297297
298298
:param query_id: Query ID.
299-
:type query_id: str | unicode
299+
:type query_id: str
300300
:return: True if kill request was sent successfully.
301301
:rtype: bool
302302
:raise arango.exceptions.AQLQueryKillError: If the send fails.
@@ -462,9 +462,9 @@ def create_function(self, name, code):
462462
"""Create a new AQL function.
463463
464464
:param name: AQL function name.
465-
:type name: str | unicode
465+
:type name: str
466466
:param code: Function definition in Javascript.
467-
:type code: str | unicode
467+
:type code: str
468468
:return: Whether the AQL function was newly created or an existing one
469469
was replaced.
470470
:rtype: dict
@@ -487,7 +487,7 @@ def delete_function(self, name, group=False, ignore_missing=False):
487487
"""Delete an AQL function.
488488
489489
:param name: AQL function name.
490-
:type name: str | unicode
490+
:type name: str
491491
:param group: If set to True, value of parameter **name** is treated
492492
as a namespace prefix, and all functions in the namespace are
493493
deleted. If set to False, the value of **name** must be a fully
@@ -552,7 +552,7 @@ def configure(self,
552552
553553
:param mode: Operation mode. Allowed values are "off", "on" and
554554
"demand".
555-
:type mode: str | unicode
555+
:type mode: str
556556
:param max_results: Max number of query results stored per
557557
database-specific cache.
558558
:type max_results: int

arango/backup.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
from __future__ import absolute_import, unicode_literals
2+
3+
__all__ = ['Backup']
4+
5+
from arango.api import APIWrapper
6+
from arango.exceptions import (
7+
BackupCreateError,
8+
BackupDeleteError,
9+
BackupDownloadError,
10+
BackupGetError,
11+
BackupRestoreError,
12+
BackupUploadError
13+
)
14+
from arango.formatter import (
15+
format_backup,
16+
format_backup_restore,
17+
format_backup_transfer
18+
)
19+
from arango.request import Request
20+
21+
22+
class Backup(APIWrapper):
23+
24+
def __init__(self, connection, executor):
25+
super(Backup, self).__init__(connection, executor)
26+
27+
def get(self, backup_id=None):
28+
"""Return backup details.
29+
30+
:param backup_id: If set, details on only the specified backup is
31+
returned. Otherwise details on all backups are returned.
32+
:type backup_id: str
33+
:return: Backup details.
34+
:rtype: dict
35+
:raise arango.exceptions.BackupGetError: If delete fails.
36+
"""
37+
request = Request(
38+
method='post',
39+
endpoint='/_admin/backup/list',
40+
data={} if backup_id is None else {'id': backup_id}
41+
)
42+
43+
def response_handler(resp):
44+
if resp.is_success:
45+
backups = resp.body['result']['list']
46+
for key in backups:
47+
backups[key] = format_backup(backups[key])
48+
return resp.body['result']
49+
raise BackupGetError(resp, request)
50+
51+
return self._execute(request, response_handler)
52+
53+
def create(self,
54+
label=None,
55+
allow_inconsistent=None,
56+
force=None,
57+
timeout=None):
58+
"""Create a backup when the global write lock can be obtained.
59+
60+
:param label: Backup label. If not given, a UUID is used.
61+
:type label: str
62+
:param allow_inconsistent: Allow inconsistent backup when the global
63+
transaction lock cannot be acquired before timeout. Default value
64+
is False.
65+
:type allow_inconsistent: bool
66+
:param force: Forcefully abort all running transactions to ensure a
67+
consistent backup when the global transaction lock cannot be
68+
acquired before timeout. Default (and highly recommended) value
69+
is False.
70+
:type force: bool
71+
:param timeout: Timeout in seconds for creating the backup. Default
72+
value is 120 seconds.
73+
:type timeout: int
74+
:return: Result of the create operation.
75+
:rtype: dict
76+
:raise arango.exceptions.BackupCreateError: If create fails.
77+
"""
78+
data = {'label': label}
79+
80+
if allow_inconsistent is not None:
81+
data['allowInconsistent'] = allow_inconsistent
82+
if force is not None:
83+
data['force'] = force
84+
if timeout is not None:
85+
data['timeout'] = timeout
86+
87+
request = Request(
88+
method='post',
89+
endpoint='/_admin/backup/create',
90+
data=data
91+
)
92+
93+
def response_handler(resp):
94+
if resp.is_success:
95+
return format_backup(resp.body['result'])
96+
raise BackupCreateError(resp, request)
97+
98+
return self._execute(request, response_handler)
99+
100+
def delete(self, backup_id):
101+
"""Delete a backup.
102+
103+
:param backup_id: Backup ID.
104+
:type backup_id: str
105+
:return: True if the backup was deleted successfully.
106+
:rtype: bool
107+
:raise arango.exceptions.BackupDeleteError: If delete fails.
108+
"""
109+
request = Request(
110+
method='post',
111+
endpoint='/_admin/backup/delete',
112+
data={'id': backup_id}
113+
)
114+
115+
def response_handler(resp):
116+
if resp.is_success:
117+
return True
118+
raise BackupDeleteError(resp, request)
119+
120+
return self._execute(request, response_handler)
121+
122+
def download(self,
123+
backup_id=None,
124+
repository=None,
125+
abort=None,
126+
config=None,
127+
download_id=None):
128+
"""Manage backup downloads.
129+
130+
:param backup_id: Backup ID used for scheduling a download. Mutually
131+
exclusive with parameter **download_id**.
132+
:type backup_id: str
133+
:param repository: Remote repository URL (e.g. "local://tmp/backups").
134+
Required for scheduling a download and mutually exclusive with
135+
parameter **download_id**.
136+
:type repository: str
137+
:param config: Remote repository configuration. Required for scheduling
138+
a download and mutually exclusive with parameter **download_id**.
139+
:type config: dict
140+
:param download_id: Download ID. Mutually exclusive with parameters
141+
**backup_id**, **repository**, and **config**.
142+
:type download_id: str
143+
:param abort: If set to True, running download is aborted. Used with
144+
parameter **download_id**.
145+
:type abort: bool
146+
:return: Download details.
147+
:rtype: dict
148+
:raise arango.exceptions.BackupDownloadError: If operation fails.
149+
"""
150+
data = {}
151+
if download_id is not None:
152+
data['downloadId'] = download_id
153+
if backup_id is not None:
154+
data['id'] = backup_id
155+
if repository is not None:
156+
data['remoteRepository'] = repository
157+
if abort is not None:
158+
data['abort'] = abort
159+
if config is not None:
160+
data['config'] = config
161+
162+
request = Request(
163+
method='post',
164+
endpoint='/_admin/backup/download',
165+
data=data
166+
)
167+
168+
def response_handler(resp):
169+
if resp.is_success:
170+
return format_backup_transfer(resp.body['result'])
171+
raise BackupDownloadError(resp, request)
172+
173+
return self._execute(request, response_handler)
174+
175+
def upload(self,
176+
backup_id=None,
177+
repository=None,
178+
abort=None,
179+
config=None,
180+
upload_id=None):
181+
"""Manage backup uploads.
182+
183+
:param backup_id: Backup ID used for scheduling an upload. Mutually
184+
exclusive with parameter **upload_id**.
185+
:type backup_id: str
186+
:param repository: Remote repository URL (e.g. "local://tmp/backups").
187+
Required for scheduling a upload and mutually exclusive with
188+
parameter **upload_id**.
189+
:type repository: str
190+
:param config: Remote repository configuration. Required for scheduling
191+
an upload and mutually exclusive with parameter **upload_id**.
192+
:type config: dict
193+
:param upload_id: Upload ID. Mutually exclusive with parameters
194+
**backup_id**, **repository**, and **config**.
195+
:type upload_id: str
196+
:param abort: If set to True, running upload is aborted. Used with
197+
parameter **upload_id**.
198+
:type abort: bool
199+
:return: Upload details.
200+
:rtype: dict
201+
:raise arango.exceptions.BackupUploadError: If upload operation fails.
202+
"""
203+
data = {}
204+
205+
if upload_id is not None:
206+
data['uploadId'] = upload_id
207+
if backup_id is not None:
208+
data['id'] = backup_id
209+
if repository is not None:
210+
data['remoteRepository'] = repository
211+
if abort is not None:
212+
data['abort'] = abort
213+
if config is not None:
214+
data['config'] = config
215+
216+
request = Request(
217+
method='post',
218+
endpoint='/_admin/backup/upload',
219+
data=data
220+
)
221+
222+
def response_handler(resp):
223+
if resp.is_success:
224+
return format_backup_transfer(resp.body['result'])
225+
raise BackupUploadError(resp, request)
226+
227+
return self._execute(request, response_handler)
228+
229+
def restore(self, backup_id):
230+
"""Restore from a local backup.
231+
232+
:param backup_id: Backup ID.
233+
:type backup_id: str
234+
:return: Result of the restore operation.
235+
:rtype: dict
236+
:raise arango.exceptions.BackupRestoreError: If restore fails.
237+
"""
238+
request = Request(
239+
method='post',
240+
endpoint='/_admin/backup/restore',
241+
data={'id': backup_id}
242+
)
243+
244+
def response_handler(resp):
245+
if resp.is_success: # pragma: no cover
246+
return format_backup_restore(resp.body['result'])
247+
raise BackupRestoreError(resp, request)
248+
249+
return self._execute(request, response_handler)

0 commit comments

Comments
 (0)