|
1
|
1 |
|
from plugin.core.backup.sources.base import BackupSource |
|
2
|
1 |
|
from plugin.core.backup.models import BackupRevision |
|
3
|
1 |
|
from plugin.core.helpers.database import db_connect, db_connection |
|
4
|
|
|
|
|
5
|
1 |
|
from datetime import datetime |
|
6
|
1 |
|
import logging |
|
7
|
1 |
|
import os |
|
8
|
|
|
|
|
9
|
1 |
|
log = logging.getLogger(__name__) |
|
10
|
|
|
|
|
11
|
|
|
|
|
12
|
1 |
|
class DatabaseBackupSource(BackupSource): |
|
13
|
1 |
|
@classmethod |
|
14
|
1 |
|
def backup(cls, group, database, tag=None, metadata=None): |
|
15
|
1 |
|
timestamp = datetime.now() |
|
16
|
|
|
|
|
17
|
|
|
# Build backup directory/name |
|
18
|
1 |
|
directory, name, path = cls.path(group, timestamp, tag) |
|
19
|
1 |
|
destination_path = path + '.db' |
|
20
|
|
|
|
|
21
|
|
|
# Ensure directory exists |
|
22
|
1 |
|
if not os.path.exists(directory): |
|
23
|
1 |
|
os.makedirs(directory) |
|
24
|
|
|
|
|
25
|
1 |
|
log.info('[%s] Backing up database to %r', group, destination_path) |
|
26
|
|
|
|
|
27
|
|
|
# Backup database |
|
28
|
1 |
|
destination = db_connect(destination_path, 'raw') |
|
29
|
|
|
|
|
30
|
|
|
# Get `database` connection |
|
31
|
1 |
|
source = db_connection(database) |
|
32
|
|
|
|
|
33
|
|
|
# Copy `source` database to `destination` |
|
34
|
1 |
|
try: |
|
35
|
1 |
|
cls._copy(group, source, destination) |
|
36
|
|
|
finally: |
|
37
|
|
|
# Close `destination` database |
|
38
|
1 |
|
destination.close() |
|
39
|
|
|
|
|
40
|
|
|
# Ensure path exists |
|
41
|
1 |
|
if not os.path.exists(destination_path): |
|
42
|
|
|
log.error('Backup failed (file doesn\'t exist)') |
|
43
|
|
|
return False |
|
44
|
|
|
|
|
45
|
|
|
# Construct revision |
|
46
|
1 |
|
revision = BackupRevision( |
|
47
|
|
|
timestamp, [ |
|
48
|
|
|
name + '.db' |
|
49
|
|
|
], |
|
50
|
|
|
|
|
51
|
|
|
tag=tag, |
|
52
|
|
|
attributes=metadata or {} |
|
53
|
|
|
) |
|
54
|
|
|
|
|
55
|
|
|
# Write backup metadata |
|
56
|
1 |
|
revision.save(path + '.bre') |
|
57
|
|
|
|
|
58
|
1 |
|
return True |
|
59
|
|
|
|
|
60
|
1 |
|
@classmethod |
|
61
|
|
|
def _copy(cls, group, source, destination): |
|
62
|
1 |
|
with destination.backup('main', source, 'main') as b: |
|
63
|
|
|
# Run until backup is completed |
|
64
|
1 |
|
while not b.done: |
|
65
|
1 |
|
b.step(100) |
|
66
|
|
|
|
|
67
|
|
|
# Report progress |
|
68
|
1 |
|
progress = float(b.pagecount - b.remaining) / b.pagecount |
|
69
|
|
|
|
|
70
|
|
|
log.debug('[%s] Backup Progress: %3d%%', group, progress * 100) |
|
71
|
|
|
|