Files
bvandeusenandClaude Opus 5.5 d065cafd11
CI / lint (push) Successful in 3s
CI / unit (push) Successful in 1m38s
CI / integration (push) Successful in 1m41s
CI / publish (push) Successful in 1m31s
feat(snmp): NAS presets for Synology and Asustor, reading every disk and volume (#5985, #5986)
A preset can now read a vendor's tables: one row per disk, volume, fan or
sensor. The scheduled poll discovers the rows by walking the device: on its
first poll, after a save, and then hourly, and only while it answers. Each row
becomes readings named by the device's own labels ("Disk 1 status"). Only the
columns a row answered are asked for.

A vendor status, whether a code (Synology) or a word (Asustor), is a state
reading. It is stored as a level (0 OK, 1 busy, 2 warning, 3 failed), so one
alert rule covers any vendor, and shown in the device's own word.

- Synology: system, power and fan status and temperature; per disk: status,
  health, temperature and bad sectors; per volume: RAID state (scrubbing,
  parity check, rebuild, degraded), free space and size.
- Asustor: per disk: status, SMART and temperature; per volume: status, free
  space and size; CPU and system temperature, free memory and fans.
  From ADM's ASUSTOR-DISK-MIB and ASUSTOR-SYSTEM-MIB.
- Linux server: plus each physical disk's 1-minute busy % (UCD-DISKIO-MIB).

Migration snmp_002_table_rows adds tables, tables_at and texts to
snmp_devices. Milestone 530.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 22:40:14 -04:00

32 lines
1.1 KiB
Python

"""SNMP devices keep the rows of their vendor tables, and states in words
A NAS preset reads a row per disk and volume, found by walking the device's
tables; the rows found, when, and each state reading's newest word are kept
on the device (milestone 530).
Revision ID: snmp_002_table_rows
Revises: snmp_001_devices
Create Date: 2026-10-17
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
revision: str = "snmp_002_table_rows"
down_revision: Union[str, None] = "snmp_001_devices"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column("snmp_devices", sa.Column("tables", sa.JSON, nullable=False, server_default="{}"))
op.add_column("snmp_devices", sa.Column("tables_at", sa.DateTime(timezone=True), nullable=True))
op.add_column("snmp_devices", sa.Column("texts", sa.JSON, nullable=False, server_default="{}"))
def downgrade() -> None:
op.drop_column("snmp_devices", "texts")
op.drop_column("snmp_devices", "tables_at")
op.drop_column("snmp_devices", "tables")