S8RuleCreationPolicy.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using Admin.NET.Plugin.AiDOP.Entity.S8;
  2. namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess;
  3. /// <summary>
  4. /// 规则创建来源。用于区分"调用方自带 SQL"与"服务端按字典生成 SQL",
  5. /// 因为两者的技术债性质与安全面完全不同。
  6. /// </summary>
  7. public static class S8RuleCreationOrigin
  8. {
  9. /// <summary>
  10. /// 裸 REST 创建(<c>POST /api/aidop/s8/config/watch-rules</c>):调用方可自带任意 expression。
  11. /// 这是新增 SQL 技术债的来源,也是注入面。
  12. /// </summary>
  13. public const string ExternalApi = "EXTERNAL_API";
  14. /// <summary>
  15. /// 配置向导生成(<c>S8ConfigDraftService.GenerateRuleAsync</c>):
  16. /// SQL 由服务端按 <c>ado_s8_monitor_object</c> / <c>ado_s8_monitor_metric</c> 字典生成,
  17. /// 标识符经 ValidateSqlIdentifier 白名单校验,调用方不提供 SQL 文本。
  18. /// </summary>
  19. public const string WizardGenerated = "WIZARD_GENERATED";
  20. }
  21. /// <summary>
  22. /// S8 规则取数模式治理。
  23. ///
  24. /// <b>S8-LEGACY-RUNTIME-RETIREMENT-1(本次收口)</b>:S8 正式确立为数据中台**消费层** ——
  25. /// 取数走 Governed Dataset → Provider → Canonical Contract,S8 不再承担源系统接入与物理连接治理。
  26. /// 因此 <see cref="S8DataAccessMode.StandardDataset"/> 成为**唯一允许运行**的取数模式。
  27. ///
  28. /// 与上一阶段(S8-LEGACY-SQL-RESIDUAL-CLEANUP-3,按创建来源分治)的差别:
  29. /// · 那一阶段只掐"调用方自带 SQL",保留向导的服务端生成 SQL,因为向导当时是在产流程;
  30. /// · 本阶段连向导通道一并收口 —— **没有治理 Dataset 就没有可运行 Rule**,不再用 Legacy SQL 兜底。
  31. ///
  32. /// <b>刻意不做的三件事</b>(改动前请先读):
  33. /// 1. **不改历史解析语义**:<c>data_access_mode</c> 为 NULL / 空白仍解析为 LEGACY_SQL
  34. /// (见 <see cref="S8DataAccessMode.Resolve"/>)。把历史行伪装成 STANDARD_DATASET
  35. /// 会让它们绕过 Enable Gate 去引用一个根本不存在的 Provider。
  36. /// 2. **不禁止停用与只读维护**:Legacy 规则必须还能被关停、被查看,否则出问题时只能去改库。
  37. /// 3. **不删历史数据**:存量 Legacy 规则与其 detection / exception 全部保留,
  38. /// 只是失去运行资格;物理清理留给后续独立批次。
  39. /// </summary>
  40. public static class S8RuleCreationPolicy
  41. {
  42. /// <summary>拒绝新增裸 SQL 规则时使用的 reason code。</summary>
  43. public const string LegacySqlCreationDisabledReason = "legacy_sql_creation_disabled";
  44. /// <summary>Legacy 规则试图进入运行态时使用的 reason code(启用 / 恢复 / 立即执行 / 调度拾取共用)。</summary>
  45. public const string LegacySqlRetiredReason = "legacy_sql_retired";
  46. /// <summary>面向用户的统一退役文案。各入口共用,避免同一条产品裁决出现多种说法。</summary>
  47. public const string LegacySqlRetiredMessage =
  48. "Legacy SQL 规则已退役。S8 仅允许运行 STANDARD_DATASET 规则:"
  49. + "请引用已注册的治理数据集(dataset_code)重建该规则;历史 Legacy 规则仍可查看与停用。";
  50. /// <summary>
  51. /// 该规则是否具备运行资格。<c>true</c> 仅当解析后的取数模式为 STANDARD_DATASET。
  52. ///
  53. /// 非法模式值(既非 LEGACY_SQL 也非 STANDARD_DATASET)同样返回 <c>false</c> 而非抛错:
  54. /// 调度器不能因为一条脏数据中断整个 tick,但也绝不能放它进执行路径。
  55. /// </summary>
  56. public static bool IsRuntimeEligible(AdoS8WatchRule rule)
  57. {
  58. if (rule == null) return false;
  59. if (!S8DataAccessMode.IsAcceptable(rule.DataAccessMode)) return false;
  60. return S8DataAccessMode.Resolve(rule.DataAccessMode) == S8DataAccessMode.StandardDataset;
  61. }
  62. /// <summary>
  63. /// 新建规则时的取数模式治理。
  64. ///
  65. /// 现在**任何来源**都只能创建 STANDARD_DATASET 规则。<paramref name="origin"/> 予以保留:
  66. /// 它仍用于区分错误文案(裸 API 自带 SQL vs 向导生成),而删除它会破坏
  67. /// <c>S8WatchRuleService.CreateAsync</c> 的既有签名契约。
  68. /// </summary>
  69. public static void EnsureCreationAllowed(AdoS8WatchRule rule, string? origin)
  70. {
  71. // STANDARD_DATASET 是唯一被接受的方向。
  72. if (IsRuntimeEligible(rule)) return;
  73. // 向导曾是唯一豁免通道(服务端按字典白名单生成 SQL)。本批一并收口,
  74. // 但给它单独文案:用户在向导里看到"你自带的 SQL 被拒"会完全对不上号。
  75. if (string.Equals(origin, S8RuleCreationOrigin.WizardGenerated, StringComparison.Ordinal))
  76. throw new S8BizException(
  77. $"[{LegacySqlRetiredReason}] 配置向导不再生成 Legacy SQL 规则。"
  78. + "当前所选监控对象没有对应的治理数据集,无法创建可运行规则;"
  79. + "请先在数据中台完成该对象的数据集治理与 Provider 上线。");
  80. throw new S8BizException(
  81. $"[{LegacySqlCreationDisabledReason}] 不再接受新建自带 SQL 的监控规则。" +
  82. $"请改用 data_access_mode={S8DataAccessMode.StandardDataset} 并引用已注册的 dataset_code;" +
  83. "历史 LEGACY_SQL 规则仍可查看与停用。");
  84. }
  85. /// <summary>
  86. /// 存量规则维护时的治理。<b>只拦"进入运行态",不拦"退出运行态"。</b>
  87. ///
  88. /// <paramref name="enabling"/> = <c>false</c>(停用 / 暂停 / 改参数)一律放行 —— 这是硬要求:
  89. /// 若关停也被拦,数据集一出问题存量规则就再也关不掉。
  90. /// </summary>
  91. public static void EnsureMaintenanceAllowed(AdoS8WatchRule rule, bool enabling)
  92. {
  93. if (!enabling) return;
  94. if (IsRuntimeEligible(rule)) return;
  95. throw new S8BizException($"[{LegacySqlRetiredReason}] {LegacySqlRetiredMessage}");
  96. }
  97. }