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
|
|
|
|