Label backups with timestamps
This commit is contained in:
parent
7ab5761959
commit
484a9593fc
|
@ -1,2 +1,4 @@
|
||||||
DATADB_ROOT = "/nexus/datadb/backups/"
|
DATADB_ROOT = "/nexus/datadb/backups/"
|
||||||
DATADB_TMP = "/nexus/datadb/tmp/"
|
DATADB_TMP = "/nexus/datadb/tmp/"
|
||||||
|
|
||||||
|
DATADB_DIR_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S.%f" # Same as isoformat(), but we need to parse it back
|
16
get_backup
16
get_backup
|
@ -6,20 +6,24 @@ from sys import exit,stdin,stdout
|
||||||
from os.path import join as pathjoin
|
from os.path import join as pathjoin
|
||||||
from os.path import exists,getsize
|
from os.path import exists,getsize
|
||||||
from common.cgi import parse_qs,parse_auth,start_response
|
from common.cgi import parse_qs,parse_auth,start_response
|
||||||
from common.datadb import DATADB_ROOT,DATADB_TMP
|
from common.datadb import DATADB_ROOT, DATADB_TMP, DATADB_DIR_TIMESTAMP_FORMAT
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
def get_backup_dir(backup_name):
|
def get_backup_dir(backup_name):
|
||||||
"""
|
"""
|
||||||
Get the absolute local path to a backup or raise an exception if none exists
|
Get the absolute local path to a backup or raise an exception if none exists. When getting a backup, sort folder
|
||||||
|
names (they're timestamps) and return newest.
|
||||||
:returns: str absolute path to backup seq /0/
|
:returns: str absolute path to backup seq /0/
|
||||||
"""
|
"""
|
||||||
backup_path = pathjoin(DATADB_ROOT, backup_name, 'data', '0', 'data')
|
backups_dir = pathjoin(DATADB_ROOT, backup_name, 'data')
|
||||||
|
|
||||||
if not exists(backup_path):
|
if not exists(backups_dir):
|
||||||
raise Exception("Backup does not exist")
|
raise Exception("Backup does not exist")
|
||||||
|
|
||||||
return backup_path
|
dirs = sorted([datetime.strptime(d, DATADB_DIR_TIMESTAMP_FORMAT) for d in os.listdir(backups_dir)])
|
||||||
|
|
||||||
|
return os.path.join(backups_dir, dirs[-1].strftime(DATADB_DIR_TIMESTAMP_FORMAT), 'data')
|
||||||
|
|
||||||
|
|
||||||
def handle_head(backup_name):
|
def handle_head(backup_name):
|
||||||
|
|
46
new_backup
46
new_backup
|
@ -6,7 +6,8 @@ from os import mkdir,rename,unlink,rmdir,utime,makedirs
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from os.path import join as pathjoin
|
from os.path import join as pathjoin
|
||||||
from common.cgi import parse_qs,parse_auth,start_response
|
from common.cgi import parse_qs,parse_auth,start_response
|
||||||
from common.datadb import DATADB_ROOT,DATADB_TMP
|
from common.datadb import DATADB_ROOT, DATADB_TMP, DATADB_DIR_TIMESTAMP_FORMAT
|
||||||
|
from datetime import datetime
|
||||||
from shutil import rmtree, move
|
from shutil import rmtree, move
|
||||||
from subprocess import Popen,PIPE
|
from subprocess import Popen,PIPE
|
||||||
from random import randint
|
from random import randint
|
||||||
|
@ -15,15 +16,18 @@ from hashlib import md5
|
||||||
from glob import iglob
|
from glob import iglob
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
def get_backup_dir(backup_name):
|
def get_backup_dir(backup_name):
|
||||||
"""
|
"""
|
||||||
Returns path to this profile's backup base dir. The base dir contains the 'data' directory
|
Returns path to this profile's backup base dir. The base dir contains the 'data' directory
|
||||||
"""
|
"""
|
||||||
return pathjoin(DATADB_ROOT, backup_name)
|
return pathjoin(DATADB_ROOT, backup_name)
|
||||||
|
|
||||||
|
|
||||||
def rotate_backups(backup_dir, max_backups=5):
|
def rotate_backups(backup_dir, max_backups=5):
|
||||||
"""
|
"""
|
||||||
In the backup dir, cascade backups. (/1/ becomes /2/, /0/ becomes /1/, etc)
|
In the backup dir, cascade backups. List the backup dir and parse folder timestamps. Sort and delete old.
|
||||||
|
Create a symlink pointing to the newest backup
|
||||||
:param backup_dir: absolute path to dir containing the numbered dirs we will be rotating
|
:param backup_dir: absolute path to dir containing the numbered dirs we will be rotating
|
||||||
:param max_backups: Max number of dirs to keep
|
:param max_backups: Max number of dirs to keep
|
||||||
:returns: Full path of new data dir
|
:returns: Full path of new data dir
|
||||||
|
@ -32,32 +36,22 @@ def rotate_backups(backup_dir, max_backups=5):
|
||||||
# Path to this profile's backup data dir
|
# Path to this profile's backup data dir
|
||||||
#profile_base_path = pathjoin(DATADB_ROOT, backup_name, 'data')
|
#profile_base_path = pathjoin(DATADB_ROOT, backup_name, 'data')
|
||||||
|
|
||||||
dirs = os.listdir(backup_dir)
|
dirs = sorted([datetime.strptime(d, DATADB_DIR_TIMESTAMP_FORMAT) for d in os.listdir(backup_dir)])
|
||||||
|
dirs.reverse()
|
||||||
if len(dirs) > 0:
|
# we the list of dirs sorted newest to oldest
|
||||||
# If there are some dirs, rotate them
|
|
||||||
# Assume all items are dirs and all dirs are named numerically
|
|
||||||
dirs = sorted([int(d) for d in dirs])
|
|
||||||
dirs.reverse() # we now have [5, 4, 3, 2, 1, 0]
|
|
||||||
|
|
||||||
for item in dirs:
|
|
||||||
if (item+1) >= max_backups:
|
|
||||||
rmtree(pathjoin(backup_dir, str(item)))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Rotate each backup once
|
|
||||||
rename(
|
|
||||||
pathjoin(backup_dir, str(item)),
|
|
||||||
pathjoin(backup_dir, str(item+1))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
if len(dirs) > max_backups:
|
||||||
|
for dirname in dirs[max_backups:]:
|
||||||
|
rmtree(pathjoin(backup_dir, dirname.strftime(DATADB_DIR_TIMESTAMP_FORMAT)))
|
||||||
|
|
||||||
|
return prepare_new_backup_dir(backup_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_new_backup_dir(backup_dir):
|
||||||
# Create the new backup dir
|
# Create the new backup dir
|
||||||
new_backup_path = pathjoin(backup_dir, "0")
|
new_backup_path = pathjoin(backup_dir, datetime.now().strftime(DATADB_DIR_TIMESTAMP_FORMAT))
|
||||||
mkdir(new_backup_path)
|
mkdir(new_backup_path)
|
||||||
mkdir(pathjoin(new_backup_path, "data"))
|
mkdir(pathjoin(new_backup_path, "data"))
|
||||||
|
|
||||||
prev_backup_path = pathjoin(backup_dir, "1")
|
|
||||||
|
|
||||||
return new_backup_path+'/data/'
|
return new_backup_path+'/data/'
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,9 +76,7 @@ def prepare_backup_dirs(backup_name, max_backups=5, rotate=True):
|
||||||
# Should always return bkname/data/0/data/
|
# Should always return bkname/data/0/data/
|
||||||
new_path = rotate_backups(backup_data_path, max_backups=max_backups)
|
new_path = rotate_backups(backup_data_path, max_backups=max_backups)
|
||||||
else:
|
else:
|
||||||
new_path = pathjoin(backup_data_path, '0', 'data') + '/'
|
prepare_new_backup_dir(backup_data_path)
|
||||||
if not exists(new_path):
|
|
||||||
makedirs(new_path)
|
|
||||||
|
|
||||||
return new_path
|
return new_path
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue