Last year |
2 |
1 |
name: Backup (full) | ||
2 |
|||||
3 |
triggers: | ||||
4 |
manual_trigger: | ||||
5 |
assignments: | ||||
6 |
backup.store: | | ||||
7 |
'jonathanroach/Backups' | ||||
8 |
backup.pattern: | | ||||
9 |
'%(backups)s/%(username)s_%(reponame)s_%(ver)d_full' | ||||
10 |
|||||
11 |
role: | ||||
12 |
policies: | ||||
13 |
- urn/api/policy/svnplace/Allow Everything | ||||
14 |
parents: | ||||
15 |
- urn/api/role/{user.username}/ | ||||
16 |
- urn/api/role/svnplace/Backup Creater | ||||
17 |
|||||
18 |
jobs: | ||||
19 |
|||||
20 |
do_backup: | ||||
21 |
runs_on: | ||||
22 |
host_instance: "{repo.primary.rootdirectory.instance.api_id}" | ||||
23 |
mapped_repo: "{repo.primary.api_id}" | ||||
24 |
steps: | ||||
25 |
- | ||||
26 |
name: Backup | ||||
27 |
python: | | ||||
28 |
import os | ||||
29 |
import subprocess | ||||
30 |
import sys | ||||
31 |
import xml.etree.ElementTree as ET | ||||
32 |
from api_api import API | ||||
33 |
|||||
34 |
repo = '{repo.urn}' | ||||
35 |
repo_user = repo.rsplit('/',2)[1] | ||||
36 |
repo_name = repo.rsplit('/',2)[2] | ||||
37 |
repo_file = '/var/svnplace/process/repo' | ||||
38 |
backup_file = os.path.abspath('./backup') | ||||
39 |
|||||
40 |
def get_repo_version(repo): | ||||
41 |
r = subprocess.run(['svn','info','--xml', 'FILE://'+repo], capture_output=True) | ||||
42 |
if r.returncode != 0: | ||||
43 |
print(r.stdout) | ||||
44 |
print(r.stderr) | ||||
45 |
return None | ||||
46 |
|||||
47 |
tree = ET.fromstring(r.stdout) | ||||
48 |
return int(tree.find('entry').attrib['revision']) | ||||
49 |
|||||
50 |
def backup_blob(ver): | ||||
51 |
return '{backup.pattern}' % {{ | ||||
52 |
'backups': '{backup.store}', | ||||
53 |
'username': repo_user, | ||||
54 |
'reponame': repo_name, | ||||
55 |
'ver': ver, | ||||
56 |
} | ||||
57 |
|||||
58 |
api = API('https://svnplace.com/api', ['~/.svnplace/config']) | ||||
59 |
|||||
60 |
repo_desc = api.repos.describe_repo(repo) | ||||
61 |
repo_ver = get_repo_version(repo_file) | ||||
62 |
|||||
63 |
try: | ||||
64 |
r = api.blobs.describe_blob('urn/blob/'+backup_blob(repo_ver)) | ||||
65 |
except FileNotFoundError: | ||||
66 |
pass | ||||
67 |
else: | ||||
68 |
print(f'{{repo_user}/{{repo_name}@{{repo_ver} is already backed up - nothing to do') | ||||
69 |
sys.exit(0) | ||||
70 |
|||||
71 |
print('Creating backup copy') | ||||
72 |
|||||
73 |
r = subprocess.run(['svnadmin','hotcopy', repo_file, backup_file]) | ||||
74 |
if r.returncode != 0: | ||||
75 |
print('Failed to complete backup') | ||||
76 |
sys.exit(1) | ||||
77 |
|||||
78 |
backup_ver = get_repo_version(backup_file) | ||||
79 |
if backup_ver is None: | ||||
80 |
print('Failed to read backup version') | ||||
81 |
sys.exit(1) | ||||
82 |
|||||
83 |
print(f'Archiving backup {{repo_user}/{{repo_name}@{{backup_ver}') | ||||
84 |
|||||
85 |
r0 = subprocess.Popen(('tar', '--strip-component', str(len(backup_file.split('/'))+1), '-cz', backup_file), stdout=subprocess.PIPE) | ||||
86 |
r1 = subprocess.run(['blobcp', '-s', repo_desc.seal.api_id, '-s', 'urn/seal/user/svnplace/Backup - Full', '-', 'blob:'+backup_blob(backup_ver)], stdin=r0.stdout) | ||||
87 |
|||||
88 |
if r1.returncode: | ||||
89 |
print('Backup failed') | ||||
90 |
sys.exit(1) | ||||
91 |
|||||
92 |
print('Backup complete') | ||||
93 |