only hold onto backups for 14 days (not 31) and show when the backups will be deleted in the control panel
This commit is contained in:
parent
bab8b515ea
commit
98fc449b49
|
@ -14,8 +14,9 @@ import dateutil.parser, dateutil.relativedelta, dateutil.tz
|
||||||
|
|
||||||
from utils import exclusive_process, load_environment, shell
|
from utils import exclusive_process, load_environment, shell
|
||||||
|
|
||||||
# settings
|
# destroy backups when the most recent increment in the chain
|
||||||
keep_backups_for = "31D" # destroy backups older than 31 days except the most recent full backup
|
# that depends on it is this many days old.
|
||||||
|
keep_backups_for_days = 14
|
||||||
|
|
||||||
def backup_status(env):
|
def backup_status(env):
|
||||||
# What is the current status of backups?
|
# What is the current status of backups?
|
||||||
|
@ -24,8 +25,8 @@ def backup_status(env):
|
||||||
# see how large the storage is.
|
# see how large the storage is.
|
||||||
|
|
||||||
now = datetime.datetime.now(dateutil.tz.tzlocal())
|
now = datetime.datetime.now(dateutil.tz.tzlocal())
|
||||||
def reldate(date):
|
def reldate(date, ref):
|
||||||
rd = dateutil.relativedelta.relativedelta(now, date)
|
rd = dateutil.relativedelta.relativedelta(ref, date)
|
||||||
if rd.days >= 7: return "%d days" % rd.days
|
if rd.days >= 7: return "%d days" % rd.days
|
||||||
if rd.days > 1: return "%d days, %d hours" % (rd.days, rd.hours)
|
if rd.days > 1: return "%d days, %d hours" % (rd.days, rd.hours)
|
||||||
if rd.days == 1: return "%d day, %d hours" % (rd.days, rd.hours)
|
if rd.days == 1: return "%d day, %d hours" % (rd.days, rd.hours)
|
||||||
|
@ -44,7 +45,7 @@ def backup_status(env):
|
||||||
backups[key] = {
|
backups[key] = {
|
||||||
"date": m.group("date"),
|
"date": m.group("date"),
|
||||||
"date_str": date.strftime("%x %X"),
|
"date_str": date.strftime("%x %X"),
|
||||||
"date_delta": reldate(date),
|
"date_delta": reldate(date, now),
|
||||||
"full": m.group("incbase") is None,
|
"full": m.group("incbase") is None,
|
||||||
"previous": m.group("incbase"),
|
"previous": m.group("incbase"),
|
||||||
"size": 0,
|
"size": 0,
|
||||||
|
@ -59,9 +60,27 @@ def backup_status(env):
|
||||||
backups[key]["encsize"] += os.path.getsize(encfn)
|
backups[key]["encsize"] += os.path.getsize(encfn)
|
||||||
|
|
||||||
# Ensure the rows are sorted reverse chronologically.
|
# Ensure the rows are sorted reverse chronologically.
|
||||||
# This is relied on by should_force_full().
|
# This is relied on by should_force_full() and the next step.
|
||||||
backups = sorted(backups.values(), key = lambda b : b["date"], reverse=True)
|
backups = sorted(backups.values(), key = lambda b : b["date"], reverse=True)
|
||||||
|
|
||||||
|
# When will a backup be deleted?
|
||||||
|
saw_full = False
|
||||||
|
deleted_in = None
|
||||||
|
days_ago = now - datetime.timedelta(days=keep_backups_for_days)
|
||||||
|
for bak in backups:
|
||||||
|
if deleted_in:
|
||||||
|
# Subsequent backups are deleted when the most recent increment
|
||||||
|
# in the chain would be deleted.
|
||||||
|
bak["deleted_in"] = deleted_in
|
||||||
|
if bak["full"]:
|
||||||
|
# Reset when we get to a full backup. A new chain start next.
|
||||||
|
saw_full = True
|
||||||
|
deleted_in = None
|
||||||
|
elif saw_full and not deleted_in:
|
||||||
|
# Mark deleted_in only on the first increment after a full backup.
|
||||||
|
deleted_in = reldate(days_ago, dateutil.parser.parse(bak["date"]))
|
||||||
|
bak["deleted_in"] = deleted_in
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"directory": basedir,
|
"directory": basedir,
|
||||||
"encpwfile": os.path.join(env['STORAGE_ROOT'], 'backup/secret_key.txt'),
|
"encpwfile": os.path.join(env['STORAGE_ROOT'], 'backup/secret_key.txt'),
|
||||||
|
@ -135,7 +154,7 @@ def perform_backup(full_backup):
|
||||||
shell('check_call', [
|
shell('check_call', [
|
||||||
"/usr/bin/duplicity",
|
"/usr/bin/duplicity",
|
||||||
"remove-older-than",
|
"remove-older-than",
|
||||||
keep_backups_for,
|
"%dD" % keep_backups_for_days,
|
||||||
"--archive-dir", "/tmp/duplicity-archive-dir",
|
"--archive-dir", "/tmp/duplicity-archive-dir",
|
||||||
"--name", "mailinabox",
|
"--name", "mailinabox",
|
||||||
"--force",
|
"--force",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<style>
|
<style>
|
||||||
|
#backup-status th { text-align: center; }
|
||||||
#backup-status tr.full-backup td { font-weight: bold; }
|
#backup-status tr.full-backup td { font-weight: bold; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
<th colspan="2">When</th>
|
<th colspan="2">When</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Size</th>
|
<th>Size</th>
|
||||||
|
<th>Deleted in...</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -56,8 +58,12 @@ function show_system_backup() {
|
||||||
if (b.full) tr.addClass("full-backup");
|
if (b.full) tr.addClass("full-backup");
|
||||||
tr.append( $('<td/>').text(b.date_str + " " + r.tz) );
|
tr.append( $('<td/>').text(b.date_str + " " + r.tz) );
|
||||||
tr.append( $('<td/>').text(b.date_delta + " ago") );
|
tr.append( $('<td/>').text(b.date_delta + " ago") );
|
||||||
tr.append( $('<td/>').text(b.full ? "full" : "incremental") );
|
tr.append( $('<td/>').text(b.full ? "full" : "increment") );
|
||||||
tr.append( $('<td style="text-align: right"/>').text( nice_size(b.encsize)) );
|
tr.append( $('<td style="text-align: right"/>').text( nice_size(b.encsize)) );
|
||||||
|
if (b.deleted_in)
|
||||||
|
tr.append( $('<td/>').text(b.deleted_in) );
|
||||||
|
else
|
||||||
|
tr.append( $('<td class="text-muted">n/a</td>') );
|
||||||
$('#backup-status tbody').append(tr);
|
$('#backup-status tbody').append(tr);
|
||||||
|
|
||||||
total_disk_size += b.size;
|
total_disk_size += b.size;
|
||||||
|
|
Loading…
Reference in New Issue