name: Initialise RepoRepository from Full Backup |
|
args: |
- |
name: reporepository |
label: Repo repository |
placeholder: Urn or api id |
python_type: str |
- |
name: host |
label: Host instance |
placeholder: Urn or api id |
python_type: str |
- |
name: blob |
label: Backup blob |
placeholder: Urn or api id |
python_type: str |
|
role: |
policies: |
- urn/api/policy/svnplace/Allow Everything |
parents: |
- urn/api/role/{user.username}/ |
- urn/api/role/svnplace/Backup Restorer |
|
jobs: |
restore: |
runs_on: |
host_instance: "{host}" |
mapped_repo: "{reporepository}" |
steps: |
- |
name: Restore |
python: | |
blob = '{escape(blob)}' |
import os |
import subprocess |
import sys |
import xml.etree.ElementTree as ET |
from api_api import API |
|
repo = '{repo.urn}' |
repo_user = repo.rsplit('/',2)[1] |
repo_name = repo.rsplit('/',2)[2] |
repo_file = '/var/svnplace/process/repo' |
|
api = API('https://svnplace.com/api', ['~/.svnplace/config']) |
|
reporepo_desc = api.repos.describe_reporepository('{reporepository}') |
if reporepo_desc.state.name != 'Initialising': |
print(f'Reporepository in wrong state:{{reporepo_desc.state}') |
sys.exit(1) |
|
# confirm backup is an actual backup |
backup_desc = api.blobs.describe_blob(blob) |
backup_seal = api.blobs.describe_seal('urn/seal/user/svnplace/Backup - Full') |
if backup_seal.id not in backup_desc.seals: |
print('Blob not a full backup') |
sys.exit(1) |
|
# restore the backup files to the root directory |
|
r0 = subprocess.Popen(['blobcp', f'blob:{{backup_desc.fullpath}', '-'], stdout=subprocess.PIPE) |
r1 = subprocess.run(['tar', '--keep-old-files', '-xzf', '-', '-C', repo_file], stdin=r0.stdout) |
|
if r1.returncode: |
print('Backup failed: could not unpack backup') |
sys.exit(1) |
|
r0.wait() |
if r0.returncode: |
print('Backup failed: reading blob failed') |
sys.exit(1) |
|
backup_desc2 = api.blobs.describe_blob(blob) |
if backup_desc2.seal_tag != backup_desc.seal_tag: |
print('Backup failed: backup changed during restore') |
sys.exit(1) |
|
repo_desc = api.repos.describe_repo(repo) |
if repo_desc.seal in backup_desc2.seals: |
# backup is of this repo... |
# leave the UUID alone |
# leave the hooks in place |
pass |
else: |
# backup is of a different repo... |
|
# replace the uuid with a new one |
r = subprocess.run(['svnadmin', 'setuuid', repo_file]) |
|
# clear all hooks |
for item in os.scandir(f'{{repo_file}/hooks/descriptions'): |
if item.is_file(): |
os.remove(item.path) |
|
api.repos.modify_reporepository('{reporepository}', state='Ready') |
|
print('Restore complete') |
|