backups plugin with NTLARS revision history; shopfloor dashboard upcoming cards and state chips
This commit is contained in:
68
plugins/backups/services/retention.py
Normal file
68
plugins/backups/services/retention.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""Revision retention.
|
||||
|
||||
Dedup already keeps growth low - a revision appears only when a setting really
|
||||
changed - so retention exists for the pathological case, not the normal one: a
|
||||
value that flaps (or two PCs alternately claiming one machine number) would
|
||||
otherwise append a revision every collection cycle forever.
|
||||
|
||||
Two independent limits, both off by default at 0:
|
||||
|
||||
retentioncount keep at most N revisions per asset per kind
|
||||
retentiondays additionally drop anything older than N days
|
||||
|
||||
The NEWEST and the OLDEST revision are never pruned. The newest is the one a
|
||||
tech restores from; the oldest is the earliest known-good baseline, which is
|
||||
usually the most valuable row in the table and the one a naive "keep last N"
|
||||
would delete first.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from shopdb.api import db
|
||||
|
||||
from ..models import BackupRevision
|
||||
|
||||
|
||||
def prune(assetid, backupkind, retentioncount=0, retentiondays=0):
|
||||
"""Delete surplus revisions for one asset+kind. Returns the number removed.
|
||||
|
||||
Caller commits. Returns 0 when both limits are disabled.
|
||||
"""
|
||||
retentioncount = int(retentioncount or 0)
|
||||
retentiondays = int(retentiondays or 0)
|
||||
if retentioncount <= 0 and retentiondays <= 0:
|
||||
return 0
|
||||
|
||||
revisions = (db.session.query(BackupRevision)
|
||||
.filter(BackupRevision.assetid == assetid,
|
||||
BackupRevision.backupkind == backupkind)
|
||||
.order_by(BackupRevision.backuprevisionid.desc())
|
||||
.all())
|
||||
if len(revisions) <= 2:
|
||||
return 0 # newest + oldest are both protected
|
||||
|
||||
newest = revisions[0]
|
||||
oldest = revisions[-1]
|
||||
protected = {newest.backuprevisionid, oldest.backuprevisionid}
|
||||
|
||||
doomed = []
|
||||
|
||||
if retentioncount > 0 and len(revisions) > retentioncount:
|
||||
# Walk from the oldest END of the middle, so the surplus dropped is
|
||||
# always the least recent, never the newest.
|
||||
for revision in revisions[retentioncount:]:
|
||||
if revision.backuprevisionid not in protected:
|
||||
doomed.append(revision)
|
||||
|
||||
if retentiondays > 0:
|
||||
cutoff = datetime.utcnow() - timedelta(days=retentiondays)
|
||||
for revision in revisions:
|
||||
if revision.backuprevisionid in protected:
|
||||
continue
|
||||
stamp = revision.collectedat or revision.createdat
|
||||
if stamp and stamp < cutoff and revision not in doomed:
|
||||
doomed.append(revision)
|
||||
|
||||
for revision in doomed:
|
||||
db.session.delete(revision)
|
||||
return len(doomed)
|
||||
Reference in New Issue
Block a user