跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

设计注记

关于 PIG 关键决策、取舍与实现边界的设计注记。

设计注记解释 PIG 为什么采用今天的行为。每篇注记都会标明决策日期、实现与发布边界、 被否决的替代方案,以及对应的当前用户文档。

这些文章提供历史与架构背景。当前命令语法和行为以 PIG 文档 为准, 交付时间线以发布注记为准。

1 - 从面向人类到 Agent-Native:PIG 的 CLI 契约

为什么 PIG 将人类文本、结构化结果、执行计划与环境上下文分开,而不是把 JSON 当成最后附加的格式选项。

决策日期: 2026-02-12
状态:pig v1.1.0 中实现,之后继续通过命令层重构收敛。
当前参考: pig 命令总览
范围: PIG 自己拥有的命令及其机器消费契约;不透明的透传命令保留原生接口。

决策

PIG 应当既适合人在终端中使用,也适合自动化 Agent 调用,而且不要求任何一方解析另一方的展示格式。 面向人的文本保持简洁、便于操作;真正拥有稳定结果的命令提供明确的 JSON/YAML 结果、状态码与执行计划。 仅仅转发外部工具的命令则保留原生输出流、提示与退出码,不能套上一层看似统一、实则失真的结果信封。

因此,Agent-Native 的含义是明确能力边界,而不是“给每条命令都加上 JSON”。

背景

PIG 最初是一套便捷的软件包管理 CLI。随着它扩展到 PostgreSQL、Patroni、pgBackRest、 Pigsty 与软件仓库操作,纯面向人的接口出现了几个问题:

  • 自动化只能抓取带颜色的自然语言文本;
  • 外层进程退出为零时,内层操作仍可能已经失败;
  • 破坏性工作流在执行前无法被审阅;
  • Agent 需要连续调用许多发现命令才能理解当前主机;
  • 包装器容易把子进程输出与结构化结果混在一起。

v1.1.0 引入了全局输出选择、稳定结果对象、执行计划与 pig context 快照。 后续重构又把这些承诺收窄到 PIG 真正能够可靠拥有的命令上。

考虑过的方案

以下三种看似简单的方案被否决:

  1. 解析人类文本。 文案、翻译、颜色与上游工具变化都会让它失效。
  2. 把所有子进程输出捕获进 JSON。 这会破坏交互程序、流式输出、终端控制与原生退出语义。
  3. 设计一个万能结果模式。 软件包事务、恢复计划、指标和环境快照拥有不同的稳定语义,强行拍平只会丢失信息。

契约

长期有效的契约是:

  • 文本是面向人的默认接口;
  • 只有在 PIG 拥有稳定结果时,命令才声明支持结构化输出;
  • 结构化 stdout 只包含一个可解析结果,诊断与被包装工具的输出进入 stderr;
  • 计划描述动作、范围、风险和预期效果,但不执行动作;
  • PIG 自己拥有的破坏性操作在缺少确认时默认失败;
  • 状态码区分用法、确认、环境、依赖与执行失败;
  • pig context 提供有边界的环境快照,不要求调用方自行拼接;
  • 透传与交互命令保持上游契约。

影响

这种分离让脚本更可靠,也让 Agent 能够依据风险与输出能力选择命令。与此同时,每个结构化字段都会成为兼容表面, stdout 纯净性需要测试,包装器也不能承诺比被委托工具更高的稳定性。

PIG 有意允许不同命令采用不同接口风格。统一很有价值,但忠实表达语义比外观一致更重要。

验证与演进

最初框架随 v1.1.0 发布。 命令层整合提交 fb93602 随后删除重复包装器, 统一计划和输出胶水。Patroni 后来改为透明透传,正好说明当上游接口已经权威时,PIG 应减少自己拥有的结构。

当前测试覆盖结构化 stdout 隔离、结果渲染、计划、确认门与环境上下文采集。

当前状态

这项原则仍然有效:应使用具体命令明确声明支持的结构化模式,不能推断全局 -o 能安全转换所有外部或交互输出流。 当前命令面与示例维护在 pig 参考文档中。

2 - 先编译和校验,再提交:原生 sty conf 流水线

为什么 pig sty conf 把 Inventory 生成视为带路径安全、结构化变更、秘密纪律和原子输出的编译流水线。

决策日期: 2026-02-18;生产契约于 2026-08-14 定稿。
状态: 已实现并随 pig v1.8.0 发布。
当前参考: pig sty conf
范围: 从受信 Pigsty 模板生成一份经过校验的静态 Inventory,不是任意 YAML 转换器。

决策

pig sty conf 应当像一台小型编译器:解析一个安全模板,读取结构,应用一组有边界的结构化变更, 校验完整候选文件,并且只在所有必要阶段成功后原子提交输出。

命令不调用旧 configure 脚本,也不回退到原始 Shell 执行。 结构化结果报告选中的输入、实际选择、变更类型与告警,但不返回生成的秘密值。

背景

模板配置看似简单,直到路径、符号链接、多 IP 占位符、固定版本模板、镜像、代理环境、生成凭据与部分有效 YAML 同时出现。文本替换流水线可能级联替换 IP,修改无关域名,泄露秘密,或在最终校验失败后截断目标文件。

输出 Inventory 可能包含管理员凭据,因此文件处理与结果渲染都属于安全边界。

考虑过的方案

  • 调用现有 Shell configure 脚本。 解析、校验和结果语义仍在 PIG 控制之外。
  • 使用全局搜索替换。 IP 与域名需要精确占位符边界和同时映射。
  • 先写文件再校验。 失败候选可能替换仍然可用的 Inventory。
  • 接受任意绝对模板路径。 命令应编译已知 Pigsty mode,而不是成为特权文件复制器。
  • 为了方便返回生成密码。 结构化日志与 Agent 轨迹不是秘密交付通道。

契约

  • 模板通过安全相对名称解析到 Pigsty 配置树下;
  • 拒绝绝对路径、目录穿越、路径逃逸,以及直接路径、符号链接父目录或硬链接造成的源/输出别名;
  • 解析与 IP 冲突检查先于外部预检;
  • 占位 IP 同时映射,无关地址保持不变;
  • 域名替换只匹配精确模板 token;
  • profile、region、proxy、locale 与 PostgreSQL 版本变更都是有边界的结构化操作;
  • 每个已知凭据标识符只生成一个随机值,结果只暴露标识符;
  • 完整候选接受原生校验,并可选执行有超时边界的 Ansible 解析;
  • 任一失败都不改变目标文件;
  • 成功结果以 0600 权限原子写入。

影响

该命令只支持定义明确的一组模板和变更,不提供任意编辑能力。 这个限制是刻意的:已有 Inventory 属于无损 pig inventory 工作流,sty conf 则拥有从已知模板进行可复现编译的职责。

固定版本模板保留自己的实际版本;通用版本请求无法应用时产生告警,而不是报告请求版本却生成另一个版本。

验证与演进

原生 configure 方向最早记录于 2026-02-18,生产实现收敛于 74e084e, 最终契约同步提交为 adc4260。 测试覆盖目录穿越与别名、同时 IP 映射、域名边界、交互与关闭输入选择、版本处理、代理和区域变更、 秘密生成与脱敏、预检顺序、校验失败、权限与原子写入。

当前状态

使用 pig sty conf 从 Pigsty 模板生成新 Inventory,使用 pig inventory 查看或编辑已有声明。 当前参数、mode 与预检行为维护在 pig sty 参考文档中。

3 - 七成正确的调优器:界定 pig pg tune 的边界

为什么 pig pg tune 只生成确定性的硬件相关核心参数,而不把自己包装成完整的生产 PostgreSQL 调优方案。

决策日期: 2026-03-21
状态: 2026-03-23 实现,并随 pig v1.3.2 发布。
当前参考: pig pg tune
范围: 为单个本地 PostgreSQL 实例生成确定性的首轮配置,不是完整的生产设计服务。

决策

pig pg tune 只回答一个有边界的问题:给定 CPU 数量、内存、磁盘容量与工作负载画像, 这台机器的 PostgreSQL 核心参数应该采用怎样的合理起点?

它追求的是“七成正确”的初始值。命令尽可能探测硬件,允许显式覆盖,计算少量高影响参数, 并可以写入 postgresql.auto.conf。它不声称能够设计复制、持久性、安全、日志、扩展、连接池或工作负载相关 SQL 行为。

背景

在还没有工作负载遥测时,运维人员仍然经常需要一套可用基线。复制静态配置会忽略机器规模; 完整调优服务则需要查询轨迹、存储特征、可用性目标和持续反馈。

PIG 已经能够定位 PostgreSQL 安装并以数据库操作系统用户运行命令。 一个小而确定的调优器符合这个边界,而且结果可检查、可复现。

考虑过的方案

  • 发布一份万能配置。 内存与并行参数必须随主机规模变化,因此否决。
  • 构建自适应自动调优器。 它需要遥测、实验、工作负载分类与回滚机制,远超本地 CLI 的边界。
  • 重写主配置文件。 这会把生成值混入发行版或运维人员维护的配置中,也不利于回滚。
  • 调节所有 PostgreSQL 参数。 很多参数表达业务、持久性、安全和拓扑决策,硬件无法替人决定。

契约

调优器遵循以下规则:

  • 硬件探测过程可观察,每个探测值都可以覆盖;
  • profile 改变公开公式,不依赖隐藏的外部状态;
  • 相同输入产生确定性结果;
  • 写文件之前可以预览,也可以获得结构化结果;
  • 生成设置仅进入自动配置表面;
  • 编辑器保留无关的现有设置与注释;
  • 数值受 PostgreSQL 与机器资源边界约束;
  • 输出明确声明 SSD 假设与建议局限。

影响

该命令适合开发机、新安装和初步容量规划,但不能证明生产数据库已经完成调优。 复制延迟、检查点行为、查询并发、缓存命中率、存储延迟、扩展与故障目标仍需要测量和人工判断。

保持小范围也让计算公式可以被充分测试,并让用户无需远程服务即可重现结果。

验证与演进

实现提交为 60eecfe, 并标记为 v1.3.2。单元测试覆盖画像计算、硬件覆盖、结果渲染和安全的 postgresql.auto.conf 编辑。 之后的静态分析清理没有改变产品边界。

当前状态

pig pg tune 仍是一项首轮工具。应用前应审阅结果;当拓扑、高可用、可观测性或安全需要协同设计时, 应使用 Pigsty 或基于真实工作负载的调优流程。当前参数与示例维护在 pig pg 参考文档中。

4 - 为什么 PIG 保持扁平的 Cobra 命令层

一个顶层命令对应 cmd 中一个文件,具体行为进入 cli 与 internal 包的源码布局决策。

决策日期: 2026-06-30
状态: 当前仍在执行的仓库架构。
当前参考: pig 命令总览源码仓库
范围: Go 源码归属与命令注册方式,而不是公开命令分类本身。

决策

cmd 包保持扁平。一个顶层命令对应一个顶层 Go 文件:pg.gopb.gopt.gope.gosty.godo.gorepo.go 等。即使命令树很复杂,也继续留在这个入口文件中, 除非另有明确的布局决策。

文件可以很长,但只应包含 Cobra 关注点:名称、别名、注解、参数、实参校验、帮助、注册和选项映射。 具体工作放入 cli/*internal/* 或其它实现包。

背景

早期命令增长产生了很多以子命令命名的小文件,也出现了多套确认、结构化输出、计划渲染和旧接口包装实现。 一些简单问题因此难以回答:顶层命令在哪里注册,某个别名由谁拥有,两段辅助代码是否在执行同一策略?

PIG 的命令族很大,但它们的公开语法是一个整体。把语法集中在一个位置更容易审查冲突, 实现包则继续按职责拆分。

考虑过的方案

  • cmd 下为每个命令建目录。 普通命令不采用,因为一个公开语法会散落在多个包中,也容易把业务逻辑放到 Cobra 附近。
  • 每个子命令一个文件。 注册、别名和继承参数将难以作为整体审阅。
  • 把所有逻辑都放进 cmd 操作逻辑依赖 Cobra 状态后,测试与复用都会变差。
  • 抽象每一行重复代码。 猜测式框架会遮蔽命令语法;只有已经稳定、跨命令复用的胶水才应共享。

契约

  • cmd/root.go 负责根命令、全局参数和顶层注册;
  • cmd/utils.go 负责共享的命令层辅助函数;
  • 每个普通顶层命令有一个对应的顶层源码文件,可以配一个同名测试文件;
  • Cobra 层校验语法和映射选项,但不执行具体操作;
  • 确认、注解、结构化输出与计划辅助逻辑只有一套实现;
  • 实现包接收普通选项并返回类型化结果或错误,不依赖 Cobra 全局状态。

影响

部分命令文件会有意保持较长。这个取舍是可接受的,因为公开接口可以作为整体审阅,而实现仍然在下层拆分。 规则也减少了别名或参数移动时的文件震荡,为 Agent 提供确定的阅读起点。

边界是架构性的,不是外观性的:把业务逻辑藏在闭包里的短 cmd 文件仍然违规; 只包含声明式命令胶水的长文件则没有问题。

验证与演进

约定记录在 9eb70db, 随后由大型命令面整合提交 fb93602 落实。 Guard 测试检查别名冲突与命令注册,实现层行为则由各包测试验证。

当前状态

这仍是新工作的仓库规则。公开命令文档统一放在本站;源码布局约束继续靠近代码保留, 确保贡献者与编码 Agent 在修改前就能看到。

5 - 危险操作只有一套语法:PIG 运维 CLI 安全契约

PIG 如何分离底层原语与编排器、显式表达破坏性意图,并防止别名或结构化输出改变操作含义。

决策日期: 2026-07-02
状态: pgpbptpitr 已于 v1.5.0 交付;2026-08-29 的 dobuild proxy 修订已随 v1.8.1 发布。
当前参考: pig pgpig pbpig pitrpig dopig build
范围: PIG 自己拥有的运维命令;透明上游命令继续采用上游的确认与退出行为。

决策

操作便利性不能模糊操作含义。PIG 明确区分底层原语与多阶段编排器,显式表达破坏性意图, 谨慎分配别名,并要求计划与结构化结果描述的动作必须和文本模式真正执行的动作一致。

最重要的例子是恢复:pig pb restore 是 pgBackRest 原语,pig pitr 则协调 Patroni、 PostgreSQL 停止、恢复、重新启动与恢复后指引。任何别名都不能让这两条路径看起来可以互换。

背景

第一代便利别名积累了不一致的位置参数、确认参数、输出处理与服务语义。 restartrestorepromotefailover 等相似词在不同层次代表完全不同的操作。 跨越层次的短别名可能把看似无害的调用变成缺少编排保护的破坏性原语。

自动化还暴露出假成功问题:包装器输出、子进程输出和结果渲染可能使用不同的成功定义。

考虑过的方案

  • 尽可能增加短别名。 冲突和跨层同义词带来的风险高于节省几个字符的价值。
  • 给所有看起来危险的单词都加确认。 对透传命令不成立,因为提示与语义必须由上游工具拥有。
  • 让编排器成为原语的便利别名。 恢复编排拥有额外的停止、验证与重启不变量,不能合并。
  • 启动内层命令后立即返回成功。 结果必须反映 PIG 拥有的完整工作流。

契约

  • 同级命令名称与别名唯一;
  • 子命令别名不能遮蔽另一个顶层命令;
  • PIG 自己拥有的破坏性操作要求显式确认,并在有意义时提供无副作用计划;
  • 命令层在产生副作用前拒绝错误或多余的位置参数;
  • 命令专用名称遵循下游 Pigsty 契约;下游 Playbook 没有显式语法时,只采用有文档说明的最窄安全边界;
  • 结构化输出与文本模式共享同一个结果和成功定义;
  • 含凭据的值不进入诊断输出;就绪或连通性失败必须保持命令失败,不能只记警告后返回成功;
  • 底层 restore 不声称管理 Patroni 或 HA 路由;
  • PITR 编排器按需停止管理器,证明 PostgreSQL 已停止,执行恢复,可选启动 PostgreSQL, 并有意保持 Patroni 停止,等待运维人员验证;
  • 额外原生参数只通过明确记录的边界传递。

影响

部分历史缩写被移除,一些脚本需要采用 cluster-first 或显式目标语法。 作为回报,命令名称保留了层次边界,计划对应真实动作,恢复自动化也不会悄悄用原语替换编排器。

这套契约不会消除操作风险。它的作用是让风险可见,并阻止便利层制造歧义。

验证与演进

规范命令契约在 c62c0f5 中进入仓库。 后续提交继续统一别名、早期校验、恢复目标、服务语义与角色检测。 Guard 测试遍历 Cobra 树,拒绝同级与跨层别名冲突;恢复测试覆盖计划、确认、停止升级、旁路恢复、 重启行为与结构化失败结果。

Patroni 后来改成透明透传,这仍遵循同一原则:PIG 只为自己拥有的工作流提供安全保证。

同一契约在 3e1603b 中扩展到 pig do 的名称与集群校验,并在 a880485 中封闭 Ansible 内置目标。软件包驱动、凭据安全且如实报告失败的 build proxy 设置进入 220ef9c, 随后由 74cb128 补齐结构化参数遮盖与机器注解,并在 de7ffd0 中把可选参数同步到机器语法。这些修改均在 Ubuntu 24.04 与 Rocky Linux 9 ARM64 Farrow 客体中完成实机测试,并在 v1.8.1 CI 通过后,从源码提交 e3d1eb4 正式发布。

当前状态

明确需要 pgBackRest 原语时使用 pig pb restore;需要受控恢复流程时使用 pig pitr。 当前语法、警告与平台要求维护在命令参考页中,而不是冻结在这篇历史记录里。

6 - 编辑声明,保留文档:无损 Pigsty Inventory

为什么 pig inventory 将 YAML 语义与源字节分离,让局部编辑能够保留注释、顺序、锚点与格式。

决策日期: 2026-07-18
状态: 已实现并随 pig v1.6.0 发布。
当前参考: pig inventory
范围: 静态 Pigsty Inventory 的查看、局部编辑、校验、比较与安全写入。

决策

PIG 同时把 pigsty.yml 视为语义声明和人工维护的源文档。语义解析器负责判断 Inventory 的含义, 原始字节则决定它的书写方式。局部编辑只替换有边界的源范围,并在原子写入前重新解析完整候选文件。

这样可以避免 YAML 工具常见的失败模式:逻辑上正确的一次编辑,却悄悄重写整份文件的注释、键顺序、 引号、锚点、块标量或换行风格。

背景

Pigsty Inventory 是长期存在的运维资产,包含拓扑、调优、凭据、注释、示例、锚点和本地有意义的顺序。 普通的“解析—修改—序列化”流程可能生成有效但无法审阅的差异,并改变运维人员没有选择的结构。

另一方面,没有语义校验的纯文本编辑又可能把无效或自相矛盾的配置写入磁盘。 设计必须同时获得源文件保真与整文正确性。

考虑过的方案

  • 使用一个 YAML 序列化器完整往返。 在真实 Pigsty 语料上,没有选定的序列化器能够逐字节保留完整源契约。
  • 用正则表达式处理 YAML。 引号、注释、别名、块标量和嵌套集合让纯文本语义判断不安全。
  • 只编辑规范化生成副本。 活跃 Inventory 属于运维人员,仍会与生成表示发生漂移。
  • 允许替换所有节点类型。 锚点、别名、标签与块标量需要比普通映射和标量更严格的处理。

契约

  • 拒绝重复键与多文档 YAML;
  • selector 只定位一个无歧义的声明片段;
  • 语义解码与源范围发现是两项独立职责;
  • 编辑从精确源 revision 开始,文件被并发修改时失败;
  • 编辑片段只进行插入上下文所必需的规范化;
  • 提交前重新解析并校验完整候选文件;
  • 写入使用同目录临时文件、sync、rename 与目录 sync;
  • 拒绝符号链接与不安全路径变化;
  • 成功编辑后将含密 Inventory 权限收紧为 0600
  • 除非命令明确属于原始文本表面,诊断、diff、计划与结构化结果都不输出声明值。

影响

编辑器比普通 YAML marshal 更复杂;当无法证明源文件保真时,一些语法有效的片段也会被有意拒绝。 换来的结果是可审阅差异:未选择部分逐字节稳定,无效 YAML 无法落盘,并发修改不会被静默覆盖。

show 仍然明确属于可能含密的接口。坦率声明这个例外,比假设一个不完整的脱敏器能识别未来所有凭据键更安全。

验证与演进

根级 Inventory 契约与既有 CMDB 边界建立于 ba6e678,实现落地于 ea43858。测试覆盖真实 Pigsty 配置语料、逐字节往返、 局部替换、受保护 YAML 形式、并发变更拒绝、原子写失败、selector、校验和无敏感值诊断。

后续重构移除了旧选项并分离校验阶段,但没有改变源文件保真模型。

当前状态

静态 Inventory 仍是主要声明表面。selector、校验 profile、结构化输出与明确标记为实验性的 CMDB 桥接, 均以当前 pig inventory 参考文档为准。

7 - 复用 Pigsty 已经拥有的 CMDB

为什么 PIG 撤销全新的 revision store 设计,转而成为 Pigsty 既有 PostgreSQL CMDB 的轻量受控适配器。

决策日期: 2026-07-18
状态: 全新 revision store 已被取代;复用既有 CMDB 的薄适配器已经实现,但仍为实验功能。
当前参考: pig inventory cmdb
范围: 与 Pigsty 既有 CMDB 交换声明,而不是再设计一个配置数据库。

决策

PIG 必须复用 Pigsty 已经提供的 CMDB。它的职责是有边界的适配:校验静态 Inventory, 将声明装载到既有表中,导出既有投影,检查一致性,并安全切换 Ansible 的静态与动态数据源。

PIG 不拥有第二套 schema、迁移历史、快照账本、CAS revision store、三方合并引擎或数据库回滚系统。

背景

早期设计把 CMDB 支持当成一个全新后端,提出独立 schema、不可变快照、revision token、合并与回滚、 备份 bundle 和数据源切换记录。方案内部逻辑完整,但出发点错误:Pigsty 已经拥有 pigstypglog schema、装载脚本、动态 Inventory 投影和数据源切换行为。

再建一套控制面会复制事实、制造同步问题,并让 PIG 对另一个项目拥有的数据模型负责。

考虑过的方案

  • 把新 revision store 保留为高级模式。 即使可选,两套权威仍然是两套权威。
  • 在新旧 schema 之间双向镜像。 冲突处理与迁移会成为永久产品责任。
  • 只用 Shell 包装既有脚本。 PIG 仍需要有边界的超时、安全连接处理、结构化计划与原子数据源切换。
  • 完全删除 CMDB 支持。 一个小型原生适配器仍能提供有价值的校验与自动化,而不重新定义 schema。

契约

  • Pigsty 既有 schema 与投影是数据模型权威;
  • PIG 通过显式数据库目标、环境配置或 service=meta 连接;
  • 凭据、DSN、SQL 正文与声明值不得进入计划或诊断;
  • check 只读;
  • init 应用既有基线,但不声称会备份现有数据库;
  • load 在事务内替换声明行,并要求显式确认;
  • dump 在没有 force 时拒绝意外覆盖;
  • enabledisable 只修改能够识别的 Ansible Inventory source 形式,并原子写入;
  • 无法识别的可执行 Inventory source 一律拒绝,不擅自重写;
  • 整个命令族继续明确标记为实验功能。

影响

纠偏删除了大量已经写出的 revision-store 代码。这是有意恢复范围,不是功能损失: 被删除的功能描述的是一个 PIG 本就不应该拥有的产品。

保留下来的适配器更小、更容易审计,也与现有 Pigsty 运维方式兼容。 它同时继承既有系统的限制:init 需要运维人员自行备份,装载声明属于替换操作,而不是协同版本控制。

验证与演进

纠正后的边界记录在 ba6e678。 废弃实现由 e0f73ed 删除, 其中包括平行 schema、snapshot、merge、revision 与 rollback 机制。 保留路径的测试覆盖 PostgreSQL 兼容性、连接信息脱敏、事务失败、摘要绑定确认、dump 安全和原子数据源切换。

当前状态

既有 CMDB 适配器已随 v1.6.0 发布,但仍为实验功能。 在真实 CMDB 上执行初始化或替换前应自行备份,并使用当前 pig inventory 文档, 不要再参考已经废弃的早期设计。

8 - 用有边界的 Grafana 客户端替代仪表盘脚本

为什么 pig sty grafana 只拥有仪表盘生命周期与偏好设置的一小段 HTTP 契约,而不成为通用 Grafana 管理客户端。

决策日期: 2026-07-18
状态: v1.6.0 实现;Grafana dashboard schema v2 支持随后在 v1.6.2 交付。
当前参考: pig sty grafana
范围: Pigsty 拥有的仪表盘目录、仪表盘与界面偏好;不是通用 Grafana provisioning。

决策

PIG 应通过有边界的原生 HTTP 客户端管理 Pigsty 随附的 Grafana 资产。 它可以检查就绪状态、列出托管资产、装载或初始化仪表盘、导出仪表盘、只清理自己拥有的资产, 并调整受支持的语言与样式偏好。

该命令不能扩张成通用 Grafana 管理 API。Datasource、organization、user、任意目录、plugin 和无关仪表盘都不属于它的所有权。

背景

旧仪表盘工作流依赖脚本和本地文件布局,几乎无法提供结构化证据来说明连接了哪个端点、 哪些资产属于自己,或为什么只完成了一部分。另一方面,如果没有严格所有权模型就开放完整 Grafana API, 可能删除用户内容,也可能在参数和诊断中泄露凭据。

只有在网络、认证、所有权与结果边界都明确时,原生客户端才值得存在。

考虑过的方案

  • 继续把 Shell 脚本作为公开接口。 超时、重定向、响应大小、脱敏和结构化结果仍会不一致。
  • 开放任意 Grafana API 调用。 这会让 PIG 变成第二个没有稳定边界的 Grafana CLI。
  • 仅凭目录名称删除。 名称不足以证明资产所有权。
  • 内置 demo 密码。 默认凭据会变成长寿命秘密,并鼓励不安全自动化。

契约

  • 每个请求都有连接与响应大小边界;
  • 拒绝不安全重定向与过大响应;
  • 认证操作前先检查公开 health;
  • 凭据来自显式安全输入、环境或 Inventory,不内置默认密码;
  • 命令行密码仅作为应急路径,并明确提示 argv 与 Shell 历史风险;
  • 错误与结构化结果不包含凭据或响应正文;
  • load 与 init 只处理 Pigsty 已知的仪表盘 bundle;
  • clean 只删除能够证明由 PIG/Pigsty 拥有的资产;
  • language 与 style 接受固定词表,并把 auto 映射到 Grafana 的 system 偏好;
  • schema v1 与 schema v2 仪表盘表示在客户端边界完成规范化。

影响

原生客户端提供了更好的计划、错误分类与自动化结果,但必须维护自己拥有的那一小段 Grafana API。 支持新仪表盘 schema 是合理演进,不代表会支持无关 Grafana 资源。

运维人员可以继续使用其它 Grafana 客户端完成通用管理,PIG 不会声称拥有这些资源。

验证与演进

原生仪表盘工作流落地于 3060485。 测试覆盖 health、认证、超时、重定向、大小限制、所有权检查、偏好请求、脱敏、部分失败与 load/dump。 Dashboard schema v2 支持随后在 67f6e3b 中加入, 并随 v1.6.2 发布。

当前状态

pig sty grafana 是 PIG 支持的 Pigsty 仪表盘生命周期入口。 命令和凭据规则以当前 pig sty 参考文档为准;边界之外的资源使用 Grafana 原生工具。

9 - 让 Patronictl 自己说话

为什么 pig pt 不再镜像 Patronictl 命令树,而是只保留少量 PIG 本地辅助功能的透明启动器。

决策日期: 2026-07-21
状态: 已实现并随 pig v1.6.0 发布。
当前参考: pig pt
范围: Patronictl 集群命令,以及 PIG 拥有的配置选择、参数设置、服务、状态和日志辅助功能。

决策

pig pt 是已安装 patronictl 的透明启动器。PIG 选择配置并分派少量本地辅助命令; 其它命令 token 及其后的所有参数原样传递,保留原生提示、终端行为、输出格式与退出码。

PIG 不再维护一份持续变化的 Patronictl 命令树副本。

背景

镜像 Patronictl 要求 PIG 复制命令、参数、位置语法、确认方式、格式和版本相关行为。 上游接口持续演进,PIG 的副本必然漂移。同一个操作通过 patronictl 与 PIG 调用时可能出现不同语义。

包装器在 Pigsty 环境中仍有价值:以数据库操作系统用户选择正确配置,提供本地服务和日志工作流, 并把一小段参数设置便利语法翻译为一次原生 edit-config 调用。

考虑过的方案

  • 继续镜像全部上游命令。 必然滞后,并重复 Patronictl 已经拥有的校验。
  • 只允许经过测试的命令白名单。 新上游命令仍要等待 PIG 发布后才能使用。
  • 把原生输出捕获成 PIG JSON。 会破坏交互编辑、流式输出、提示、终端保真和上游 schema。
  • 完全删除 pig pt 确定性配置选择与本地 Pigsty 辅助能力仍然有价值。

契约

  • 第一个非选项命令 token 决定本地分派还是透传;
  • set、本地 service shortcut、statuslog 由 PIG 拥有;
  • 其它命令和剩余 token 原样转发;
  • pig pt -- COMMAND ... 显式绕过本地名称冲突;
  • 包装器参数必须出现在原生命令 token 之前;
  • 原生 help 可以在没有本地 Patroni 配置时运行;
  • Patronictl 拥有交互提示、原生 --format 和退出码;
  • 会产生原生参数歧义的 PIG 全局结构化输出被明确拒绝;
  • 配置按确定顺序解析,进程以数据库系统用户运行。

影响

自动化需要采用 Patronictl 的 cluster-first 位置语法与原生输出参数。 部分 PIG 专有别名和结果 schema 被移除。换来的好处是:新 Patronictl 功能无需等待 PIG 发布, 行为也不再依赖滞后的包装器实现。

本地 set 辅助功能有意保持很小:它只分类 Patroni 标量键与 PostgreSQL 参数,然后执行一次原生 edit-config。

验证与演进

重写提交为 6cbc23b。 测试覆盖 token 边界、argv 原样保留、配置优先级、数据库用户执行、原生退出码、无配置 help、 输出模式拒绝、-- 逃逸与本地辅助命令冲突。最终 help 路径修正在 v1.6.0 前完成。

当前状态

透传命令语法以 Patronictl 自身文档为准;PIG 的配置选择与本地辅助功能以 pig pt 为准。 不能用 PIG -o json 代替 Patronictl 原生 --format json

10 - PIG 2.0 产品方向:一份提案,而不是发布契约

PIG 2.0 的候选边界:稳定的 Pigsty 初始化前门、可验证 Catalog 客户端,以及保持显式部署的薄编排层。

决策日期: 2026-08-13
状态: 等待 owner 审议的提案;尚未实现,也不是 PIG 2.0 发布承诺。
当前参考: PIG 文档与当前 v1.8.1 发布
范围: 未来 PIG 2.0 / Pigsty 5.0 的候选产品边界与验证门槛。

决策

提案方向是让 PIG 成为从空白控制节点到经过校验、可以部署的 Pigsty Inventory 的稳定初始化前门。 PIG 拥有 Catalog 选择、解析、计划、有边界的执行编排、结构化结果与脱敏 receipt; 软件包事务、配置应用与基础设施状态继续委托给 DNF/APT、Ansible 和未来的 provider 工具。

提案有意保留 PIG 的独立价值:repoextinstall 在没有 Pigsty 项目时也必须可用。 它也保留显式部署同意:未来的 pig sty setup 可以下载、引导与生成配置,但不能在用户没有单独调用部署时 自动执行多节点 deploy。

背景

到 v1.8.0,PIG 已经能够下载 release、原生引导控制节点、编译 Inventory、管理仓库与扩展, 并执行部分运维操作。产品仍存在几个接缝:

  • repository、package alias、extension、route 与 Pigsty 元数据可以独立变化;
  • 项目没有明确 Catalog 身份,无法防止后续解析受全局更新影响;
  • 路由选择与仓库安全还不是一套可见产品契约;
  • 初始化路径上的执行结果还没有形成持久、脱敏的 receipt;
  • PIG、Pigsty、Catalog schema、操作系统与 Ansible 的兼容性需要统一发布矩阵,而不是分散假设。

提案把这些接缝定义为 2.0 问题,而不是把大版本当作随意改名或重造既有工具的许可。

考虑过的方案

  • 把 PIG 变成单体配置与状态引擎。 Inventory、Catalog authoring、包管理器、Ansible 与 provider 已经分别拥有不同事实,因此否决。
  • 让 Pigsty 运行时依赖 PIG 或 pgext checkout。 Pigsty release 必须依靠版本化生成产物独立工作。
  • 让 setup 自动部署。 生成并校验配置与修改远程节点属于不同的同意边界。
  • 重新实现 DNF/APT failover 或 Ansible 执行。 PIG 应选择输入并解释结果,而不是成为另一个包管理器或配置引擎。
  • 让 Vagrant/Terraform 统一阻塞 2.0。 Lab provider 状态语义不同,也不决定核心初始化路径。
  • 立即发明万能 sty plan 至少两个 PIG 自有工作流证明同一计划 schema 可复用后再讨论。

契约

如果获得批准,产品方向将遵循以下边界:

  • 每类事实只有一个权威:Inventory 负责集群声明,Catalog authoring source 负责产品元数据, project lock 负责选中 snapshot 身份,receipt 负责观测结果,provider 负责实时状态;
  • PIG 拥有 Catalog schema、校验、客户端、resolver 与选择逻辑,但不拥有所有 authoring 数据库;
  • sty setup 组合既有 init、boot、configure use case,不复制实现;
  • setup 在 Inventory 校验后停止,deploy 继续显式执行;
  • 独立命令跟踪兼容 Catalog channel,Pigsty 项目在成功 setup 或 conf 提交后 pin 当时的 snapshot;
  • 普通命令不隐式改写已有 project lock;
  • 路由选择来自显式配置或有边界的首次判断,不构建持续 GeoIP、云 IMDS 或后台测速服务;
  • 软件包下载重试与 endpoint failover 由 DNF/APT 负责;
  • 执行 artifact 版本化并脱敏,raw 上游模式保持原生输出流与退出语义;
  • doctor 保持诊断角色,不获得默认修复权限;
  • 未来 lab 支持只做薄适配,PIG 不拥有 Terraform state。

影响

提案会让首次使用路径更清晰,也让元数据选择可以审计。与此同时,它会新增 snapshot identity、 project lock、迁移规则、trust policy、receipt 和兼容矩阵等持久契约。 这些契约会显著增加测试与发布负担,不能作为松散功能各自交付。

一些有吸引力的工作被明确设为可选或延期。Ansible event bridge 只有在脱敏与兼容实验通过后才是目标; doctor/support bundle 与 lab adapter 属于 GA 之后;EL7 支持档位仍是 owner 决策,不是隐含兼容承诺。

验证与演进

提案成为发布契约前需要以下证据:

  • 覆盖声明 Linux 目标的原生 onboarding VM 矩阵;
  • Catalog 签名、过期、回滚、混装与离线场景的对抗测试;
  • 证明 Pig、Pigsty、pgext 生成消费者不会漂移的语义 diff;
  • no_log 与秘密零泄露的 Ansible callback 实验;
  • 全球、中国、代理和受限网络环境的路由选择测试;
  • 修改安全默认值前的仓库签名矩阵;
  • 1.x 到 2.0 的布局、lock 与混合版本迁移演练;
  • 与明确兼容矩阵绑定的 schema 和结构化输出 fixture。

当前实现基线是 v1.8.0。 该版本已经包含原生 boot 与 configure,但没有实现提案中的 Catalog v2、project pin、setup 命令、 event receipt 或 2.0 迁移契约。

当前状态

这是一份公开提案记录,不是发布公告。当前用户应继续遵循 v1.8.1 文档。 Catalog v2 安全方案、typed overlay、路径布局细节、EL7 支持档位、event bridge 可行性与最终 2.0 范围, 都需要明确决策和实验结果,之后才能作出实现或发布声明。

11 - Catalog v2 提案:不可变 typed snapshot,而不是更大的 CSV

一套候选的可验证 Catalog 模型:typed target、内容寻址 snapshot、显式激活、项目 pin 与离线导入。

决策日期: 2026-08-13
状态: 实现前提案;安全机制、overlay 范围、打包方式与路径 ADR 仍未决定。
当前参考: pig extpig repo描述 v1 Catalog 行为。
范围: PIG 2.0 产品元数据的候选发布与消费模型,不包含 Inventory 或实时系统状态。

决策

Catalog v2 应当是一份由多个 typed target 组成的不可变、可验证 snapshot。 Manifest 将平台、仓库、路由、package alias、扩展、兼容性、Pigsty release 与公钥元数据绑定到精确字节。 所有候选 target 一起校验,通过同一个 pointer 激活,避免新仓库 Catalog 与旧扩展矩阵被静默混装。

Snapshot digest 是最终身份。Package、system、user、portable 与 project scope 保存或选择的是同一份 已验证内容,而不是把无关 base snapshot 合并成一份人工 Catalog。

背景

v1 Catalog 很实用,但相关事实散布在 embedded CSV、repository YAML、Pigsty 变量、生成站点和 reload 路径中。 部分字段重复维护可推导信息,extension matrix 也把几个独立身份压缩到同一条记录。 独立更新后,很难证明 repository、package、extension 与 compatibility 数据来自同一次发布。

因此,Catalog v2 首先是发布与信任问题,而不仅是换一种序列化格式。

考虑过的方案

  • 制作更大的 extension.csv 或一个巨型 YAML。 不同 target 类型演进速度不同,也无法独立流式处理并整体激活。
  • 立即使用 SQLite、protobuf 或定制二进制矩阵。 当前数据量没有证明值得承担新的运行时与调试成本。
  • 按字段合并 system、user、project base snapshot。 结果没有单一 publisher、digest、兼容声明或签名。
  • 只把 active 或 project pin 内容放在 cache。 删除缓存不能破坏持久的用户或项目决定。
  • 允许 user file 遮蔽官方 trust root。 安全 policy 是约束,不是普通的后写覆盖偏好。
  • 后台静默更新并激活。 元数据变化可能改变包解析,必须是可观察操作。

契约

候选 snapshot 契约是:

  • Manifest 与小型 target 使用确定性 UTF-8 JSON,大型稀疏 target 使用 JSONL;
  • 直接校验原始 manifest bytes 与 target length/hash,避免 parse 后重新序列化产生歧义;
  • Manifest 包含 schema、单调安全版本、创建时间、过期时间、channel 和 PIG/Pigsty 兼容范围;
  • 始终提供 embedded rescue baseline;
  • package-owned baseline、durable snapshot store、可变状态 pointer 与可清理下载 cache 使用不同路径;
  • Linux 遵循 FHS/XDG,macOS 使用 Application Support 与 Caches,portable PIG_HOME 仍区分 config、data、state、cache 与 run;
  • project lock 记录 snapshot 身份和有序 overlay,已验证 snapshot 物化到持久 project support data;
  • 选择 digest 与寻找该 digest 的 bytes 是两个独立算法;
  • 低层 scope 只能收紧 system security policy,不能静默放宽;
  • 更新下载到私有 staging,校验每一层,sync 后移动到内容寻址 store,再原子替换 active pointer;
  • 失败时保留此前 active snapshot;
  • user/system active channel 更新不会移动 project pin;
  • 离线导出包含验证元数据和公开 trust material,绝不包含私钥;
  • ext reloadrepo reload 可以在一个兼容周期内映射到整体 snapshot update, 但不能分别激活 target。

运行时 Catalog 明确不包含 Inventory、凭据、实时探测、已安装包状态、Ansible event、provider state、 危险操作确认和不属于产品决策的短期波动指标。

影响

Typed target 让所有权与校验更清晰,内容寻址让 rollback 与 airgap import 可审计。 Project materialization 避免部署依赖某个用户的全局 cache。独立 OS package 可以更新只读 baseline, 而不改变 active user selection。

代价是一套更大的发布协议:key rotation、expiry、rollback protection、GC、路径权限、迁移、 包管理器生命周期、overlay 冲突与跨仓 generator 都会成为兼容敏感工作。

Extension 模型也必须分离 SQL extension 身份、上游项目、distribution/build unit、版本化 release、 OS package offer、目标可用性和展示 policy。Aggregate platform support、required_by 等派生字段应由 generator 计算,而不是维护第二份事实。

验证与演进

实现前必须通过 ADR 在 go-tuf 与最小 signed manifest 之间作出选择。 两个候选必须通过同一组威胁测试:坏签名、过期元数据、回滚、target 替换、snapshot 混装、截断下载与离线验证。 如果都不能通过,Catalog v2 就不能作为 2.0 发布功能。

其它门槛覆盖 FHS/XDG/macOS/portable 路径、root 与非 root 权限、只读 home/project、符号链接替换、 磁盘写满与并发激活、package upgrade/remove 语义、删除全局 cache 后 project 仍能工作, 以及当前扩展和可用矩阵的无损迁移。

当前源码基线仍是 v1.8.0, 其 embedded 与可 reload 的 v1 Catalog 继续定义已发布行为。

当前状态

今天没有任何 Catalog v2 命令、manifest、trust root、store 布局、project lock 或迁移格式属于已发布 PIG 契约。 如果 typed overlay 的冲突与信任规则无法得到证明,应从 2.0 中删去;完整自定义签名 channel 比松散、未验证的 patch 更安全。当前安装与 Catalog 行为仍以 pig extpig repo为准。

12 - 把 Pigsty 控制节点引导设计成可恢复事务

为什么 pig sty boot 在提权前解析来源、分离硬失败与收尾告警,并在软件源准备失败时恢复仓库定义。

决策日期: 2026-08-14
状态: 已实现并随 pig v1.8.0 发布。
当前参考: pig sty boot
范围: 准备 Pigsty 控制节点及其软件来源,不包括部署数据库集群。

决策

pig sty boot 应当是一套原生、能够处理失败的控制节点引导工作流。 它在提权前解析显式来源,准备在线或离线仓库,只安装必要的控制节点软件包,证明 Ansible 真正可用, 并执行有边界的收尾检查。

仓库替换具有事务语义:软件包准备失败时恢复原有仓库定义。 可选便利功能可以告警,但无效的显式输入、软件包失败和最终不可用的 Ansible 环境属于硬失败。

背景

旧命令把工作委托给 Shell bootstrap 脚本,来源选择、下载、sudo 边界、仓库回滚、错误分类与结构化自动化都难以观察。 仅仅存在 ansible-playbook 二进制也可能产生假就绪,因为它使用的 Python 环境可能缺少必要模块。

离线安装还带来另一种歧义:控制节点已经可用时,仍可能需要为后续节点准备本地仓库。

考虑过的方案

  • 继续调用旧脚本。 PIG 无法拥有事务,也无法可靠解释部分失败。
  • 要求整个命令一开始就以 root 运行。 显式下载与来源校验不需要权限,应在一次有边界的提权前完成。
  • 把 Ansible 二进制存在视为就绪。 可执行文件使用的 Python 环境可能缺少必要模块。
  • Ansible 已就绪时跳过仓库工作。 显式离线来源的 staging 是独立的请求效果。
  • 把所有收尾检查设为硬失败。 locale 便利、本机 SSH 修复或目录初始化失败,不一定让控制节点不可用。

契约

  • 显式本地路径和 URL 必须校验,失败时不能悄悄回退到在线模式;
  • 自动发现的离线来源必须通过所有者与权限检查;
  • 已提交的本地仓库可以优先于选定的软件包;
  • 下载与受限归档解压使用原生有边界实现;
  • 离线包必须包含 pigsty/repo_complete 哨兵;附加根目录先预检并在 pigsty 前 rename, 冲突与中断残留都失败关闭,由操作员清理;
  • 来源解析完成后只进行一次提权,并可禁止或要求非交互提权;
  • 软件包准备失败时,被替换的仓库定义可以恢复;
  • 就绪检查实际执行 Ansible,并验证它会使用的 Python 模块;
  • 结果区分 ready、offline、online 与 existing 模式;
  • 硬失败和收尾告警使用不同结构化字段;
  • bootstrap 不声称 Pigsty 部署已经成功。

影响

原生工作流比脚本启动器更大,但副作用与回滚状态可见。 它能够在已经可用的控制节点上继续 staging 离线内容,也能为自动化提供稳定结果而不隐藏可选问题。

该命令仍不能证明 Pigsty 已经部署。控制节点就绪、Inventory 生成、部署和真实服务验证是不同门槛。

验证与演进

原生实现落地于 222616e, 并在 74e084e 中继续收敛。 测试覆盖来源优先级、权限检查、受限解压、sudo 自重启、仓库回滚、locale 修复、Ansible/Python 就绪、 本机 SSH、初始化、告警分类与结构化结果。v1.8.0 发布页记录了交付状态。

一项尚未发布的 v1.8 后续改进把离线包路径扩展为保留多个安全顶层仓库。它继续使用既有哨兵 契约,明确不增加 manifest 或恢复 journal。该改进已经实现并通过本地测试,但不属于上面的 v1.8.0 发布声明。

当前状态

pig sty boot 负责准备控制节点,不运行 deploy.yml,也不证明数据库服务已经就绪。 来源模式、环境控制和后续步骤以当前 pig sty 文档为准。