"""DNS write control — decouple DNS requests from the prod-cloud freeze. Revision ID: 386 Revises: 385 Create Date: 2026-07-06 Why this exists --------------- Self-service DNS requests (create / update / delete a record via the Feishu approval → execute path) used to gate their cloud write on ``cmdb.prod_cloud_writes_enabled`` — the prod-IAM kill-switch. That coupled two unrelated things: an incident freeze meant to stop accidental prod-IAM mutation ALSO failed every already-approved DNS change, with no auto-resume, stranding requests at ``failed``. A DNS record edit is low blast-radius and trivially reversible, so it gets its own switch: ``cmdb.dns_writes_enabled``. Unlike the IAM lock, its safe/normal posture is ENABLED — it is seeded ``true`` and the enforcement code (``app/domains/cmdb/prod_write_lock.dns_writes_enabled``) treats a MISSING row as enabled too, so DNS requests execute by default. Flipping it to ``false`` freezes DNS writes specifically, without touching cloud-IAM writes. Idempotency ----------- ``INSERT ... ON DUPLICATE KEY UPDATE description`` so re-running refreshes the description without overwriting an admin's flipped value. """ from __future__ import annotations import json import sqlalchemy as sa from alembic import op revision = "386" down_revision = "385" branch_labels = None depends_on = None SETTING_KEY = "cmdb.dns_writes_enabled" DEFAULT_VALUE = True DESCRIPTION = ( "DNS 解析记录写操作总开关。true(默认)= 允许:已审批通过的 DNS 新增 / " "修改 / 删除申请会正常执行。false = 锁定:已审批的 DNS 变更不会执行," "失败的申请可在 IT 管理员解除锁定后点「重跑」恢复(审批仍有效,无需" "重新发起)。此开关与生产云账号写开关(cmdb.prod_cloud_writes_enabled)" "相互独立 —— 冻结云 IAM 写操作不再会连带停掉 DNS 变更。系统自动化不受影响。" ) def _table_exists(bind, name: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :n" ), {"n": name}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "platform_settings"): return bind.execute( sa.text( "INSERT INTO platform_settings (`key`, value, description, " "created_at, updated_at) " "VALUES (:k, :v, :d, NOW(), NOW()) " "ON DUPLICATE KEY UPDATE " "description = VALUES(description), updated_at = NOW()" ), { "k": SETTING_KEY, "v": json.dumps(DEFAULT_VALUE), "d": DESCRIPTION, }, ) def downgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "platform_settings"): return bind.execute( sa.text("DELETE FROM platform_settings WHERE `key` = :k"), {"k": SETTING_KEY}, )