48 lines
1.8 KiB
Python
48 lines
1.8 KiB
Python
"""backups: record when a configuration was last confirmed unchanged.
|
|
|
|
Dedup means an unchanged config writes NO revision, so `collectedat` moves only
|
|
when something changes. A machine whose settings have been stable for six months
|
|
therefore has a six-month-old newest revision and is entirely healthy - and
|
|
ShopDB had no way to tell it apart from a machine whose backup stopped running
|
|
six months ago. The evidence that a check happened existed only in a log file on
|
|
the PC.
|
|
|
|
`lastseenat` records the check rather than the change. It is touched on every
|
|
matching post, including the no-op that writes nothing else.
|
|
|
|
Backfilled from `collectedat` (falling back to `createdat`) so existing rows
|
|
start from the last moment we can actually prove the config was current, rather
|
|
than from now - claiming a fresh check that never happened would be worse than
|
|
saying nothing.
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = 'backups0002lastseenat'
|
|
down_revision = 'backups0001baseline'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
inspector = sa.inspect(op.get_bind())
|
|
if 'backuprevisions' not in inspector.get_table_names():
|
|
return
|
|
columns = {c['name'] for c in inspector.get_columns('backuprevisions')}
|
|
if 'lastseenat' not in columns:
|
|
op.add_column('backuprevisions',
|
|
sa.Column('lastseenat', sa.DateTime(), nullable=True))
|
|
op.execute('UPDATE backuprevisions '
|
|
'SET lastseenat = COALESCE(collectedat, createdat)')
|
|
|
|
|
|
def downgrade():
|
|
inspector = sa.inspect(op.get_bind())
|
|
if 'backuprevisions' not in inspector.get_table_names():
|
|
return
|
|
columns = {c['name'] for c in inspector.get_columns('backuprevisions')}
|
|
if 'lastseenat' in columns:
|
|
op.drop_column('backuprevisions', 'lastseenat')
|