feat: agent updates from SAC, poll config, SSH/WinRM fallback (0.12.0)

Add agent update settings, pending self-update via poll, desired config per host, and automatic or manual SSH/WinRM fallback when agents do not report agent.update events.
This commit is contained in:
2026-06-20 15:52:10 +10:00
parent 75f4c475df
commit cd2f27792d
24 changed files with 1494 additions and 15 deletions
@@ -0,0 +1,98 @@
"""agent control plane: host update/config + ui agent-update settings
Revision ID: 020
Revises: 019
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects.postgresql import JSONB
revision: str = "020"
down_revision: Union[str, None] = "019"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column(
"hosts",
sa.Column("pending_agent_update", sa.Boolean(), nullable=False, server_default=sa.false()),
)
op.add_column(
"hosts",
sa.Column("pending_update_requested_at", sa.DateTime(timezone=True), nullable=True),
)
op.add_column(
"hosts",
sa.Column("pending_update_target_version", sa.String(length=64), nullable=True),
)
op.add_column(
"hosts",
sa.Column("agent_config", JSONB, nullable=True),
)
op.add_column(
"hosts",
sa.Column("agent_config_revision", sa.Integer(), nullable=False, server_default="0"),
)
op.add_column(
"hosts",
sa.Column("agent_update_state", sa.String(length=32), nullable=True),
)
op.add_column(
"hosts",
sa.Column("agent_update_last_at", sa.DateTime(timezone=True), nullable=True),
)
op.add_column("hosts", sa.Column("agent_update_last_error", sa.Text(), nullable=True))
op.add_column(
"ui_settings",
sa.Column("agent_update_mode", sa.String(length=16), nullable=False, server_default="gpo"),
)
op.add_column(
"ui_settings",
sa.Column("agent_update_fallback_enabled", sa.Boolean(), nullable=False, server_default=sa.true()),
)
op.add_column(
"ui_settings",
sa.Column("agent_update_fallback_minutes", sa.Integer(), nullable=False, server_default="15"),
)
op.add_column(
"ui_settings",
sa.Column("agent_recommended_rdp_version", sa.String(length=64), nullable=True),
)
op.add_column(
"ui_settings",
sa.Column("agent_recommended_ssh_version", sa.String(length=64), nullable=True),
)
op.add_column(
"ui_settings",
sa.Column("agent_min_rdp_version", sa.String(length=64), nullable=True),
)
op.add_column(
"ui_settings",
sa.Column("agent_min_ssh_version", sa.String(length=64), nullable=True),
)
op.add_column("ui_settings", sa.Column("win_agent_update_script", sa.Text(), nullable=True))
def downgrade() -> None:
op.drop_column("ui_settings", "win_agent_update_script")
op.drop_column("ui_settings", "agent_min_ssh_version")
op.drop_column("ui_settings", "agent_min_rdp_version")
op.drop_column("ui_settings", "agent_recommended_ssh_version")
op.drop_column("ui_settings", "agent_recommended_rdp_version")
op.drop_column("ui_settings", "agent_update_fallback_minutes")
op.drop_column("ui_settings", "agent_update_fallback_enabled")
op.drop_column("ui_settings", "agent_update_mode")
op.drop_column("hosts", "agent_update_last_error")
op.drop_column("hosts", "agent_update_last_at")
op.drop_column("hosts", "agent_update_state")
op.drop_column("hosts", "agent_config_revision")
op.drop_column("hosts", "agent_config")
op.drop_column("hosts", "pending_update_target_version")
op.drop_column("hosts", "pending_update_requested_at")
op.drop_column("hosts", "pending_agent_update")