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