"""Add diskhealthjson to endpointstates. Per-drive health, kept separate from disksjson. That column answers "how full is this drive"; this one answers "is this drive dying". Merging them would mean a capacity collection failure and a health collection failure could not be told apart, and the two come from different WMI sources with different failure modes. JSON rather than scalar columns because a machine has a variable number of drives and each carries its own verdict, and because the agent reports the same drive from two sources - MSFT_PhysicalDisk for NVMe and Win32_DiskDrive for ATA/SATA - which the server keeps side by side rather than collapsing. MEDIUMTEXT for consistency with the other snapshot columns on this table. Nullable with no backfill. A drive whose health has never been reported is not a healthy drive, and defaulting to an empty list would read as "no disks have problems" on every endpoint that predates this column. Idempotent: the column-add checks the live schema first, so a re-run and a db.create_all() site both stay clean on strict MySQL 8. """ from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision = 'endpoints0014diskhealth' down_revision = 'endpoints0013inventorycolumns' branch_labels = None depends_on = None TABLE_NAME = 'endpointstates' COLUMN_NAME = 'diskhealthjson' def _has_column(table_name, column_name): from sqlalchemy import inspect inspector = inspect(op.get_bind()) if not inspector.has_table(table_name): return False return any(col['name'] == column_name for col in inspector.get_columns(table_name)) def upgrade(): if not _has_column(TABLE_NAME, COLUMN_NAME): op.add_column( TABLE_NAME, sa.Column(COLUMN_NAME, sa.Text(length=16777215), nullable=True)) def downgrade(): if _has_column(TABLE_NAME, COLUMN_NAME): op.drop_column(TABLE_NAME, COLUMN_NAME)