1 | name: Initialise RepoRepository from Full Backup |
2 | |
3 | args: |
4 | - |
5 | name: reporepository |
6 | label: Repo repository |
7 | placeholder: Urn or api id |
8 | python_type: str |
9 | - |
10 | name: host |
11 | label: Host instance |
12 | placeholder: Urn or api id |
13 | python_type: str |
14 | - |
15 | name: blob |
16 | label: Backup blob |
17 | placeholder: Urn or api id |
18 | python_type: str |
19 | |
20 | role: |
21 | policies: |
22 | - urn/api/policy/svnplace/Allow Everything |
23 | parents: |
24 | - urn/api/role/{user.username}/ |
25 | - urn/api/role/svnplace/Backup Restorer |
26 | |
27 | jobs: |
28 | restore: |
29 | runs_on: |
30 | host_instance: "{host}" |
31 | mapped_repo: "{reporepository}" |
32 | steps: |
33 | - |
34 | name: Restore |
35 | python: | |
36 | blob = '{escape(blob)}' |
37 | import os |
38 | import subprocess |
39 | import sys |
40 | import xml.etree.ElementTree as ET |
41 | from api_api import API |
42 | |
43 | repo = '{repo.urn}' |
44 | repo_user = repo.rsplit('/',2)[1] |
45 | repo_name = repo.rsplit('/',2)[2] |
46 | repo_file = '/var/svnplace/process/repo' |
47 | |
48 | api = API('https://svnplace.com/api', ['~/.svnplace/config']) |
49 | |
50 | reporepo_desc = api.repos.describe_reporepository('{reporepository}') |
51 | if reporepo_desc.state.name != 'Initialising': |
52 | print(f'Reporepository in wrong state:{{reporepo_desc.state}') |
53 | sys.exit(1) |
54 | |
55 | # confirm backup is an actual backup |
56 | backup_desc = api.blobs.describe_blob(blob) |
57 | backup_seal = api.blobs.describe_seal('urn/seal/user/svnplace/Backup - Full') |
58 | if backup_seal.id not in backup_desc.seals: |
59 | print('Blob not a full backup') |
60 | sys.exit(1) |
61 | |
62 | # restore the backup files to the root directory |
63 | |
64 | r0 = subprocess.Popen(['blobcp', f'blob:{{backup_desc.fullpath}', '-'], stdout=subprocess.PIPE) |
65 | r1 = subprocess.run(['tar', '--keep-old-files', '-xzf', '-', '-C', repo_file], stdin=r0.stdout) |
66 | |
67 | if r1.returncode: |
68 | print('Backup failed: could not unpack backup') |
69 | sys.exit(1) |
70 | |
71 | r0.wait() |
72 | if r0.returncode: |
73 | print('Backup failed: reading blob failed') |
74 | sys.exit(1) |
75 | |
76 | backup_desc2 = api.blobs.describe_blob(blob) |
77 | if backup_desc2.seal_tag != backup_desc.seal_tag: |
78 | print('Backup failed: backup changed during restore') |
79 | sys.exit(1) |
80 | |
81 | repo_desc = api.repos.describe_repo(repo) |
82 | if repo_desc.seal in backup_desc2.seals: |
83 | # backup is of this repo... |
84 | # leave the UUID alone |
85 | # leave the hooks in place |
86 | pass |
87 | else: |
88 | # backup is of a different repo... |
89 | |
90 | # replace the uuid with a new one |
91 | r = subprocess.run(['svnadmin', 'setuuid', repo_file]) |
92 | |
93 | # clear all hooks |
94 | for item in os.scandir(f'{{repo_file}/hooks/descriptions'): |
95 | if item.is_file(): |
96 | os.remove(item.path) |
97 | |
98 | api.repos.modify_reporepository('{reporepository}', state='Ready') |
99 | |
100 | print('Restore complete') |
101 | |