Repository navigation
fix(deploy): let the edge read logs under /home with ProtectHome=read-only - #470
Dragonzz27 wants to merge 4 commits into
Conversation
…-only ProtectHome=true masks /home, /root and /run/user with an empty tmpfs inside the service mount namespace. The logs plugin spawns promtail as a subprocess, so it inherits that namespace and cannot see any file under /home: promtail reports "Adding target" and then never opens the path, which makes log collection fail silently for any application logging into a home directory. read-only keeps the protection that actually matters here, since those paths stay unwritable to the agent, while leaving them readable, which is all log scraping needs. Both unit definitions change together: the template shipped as ongrid-edge.service and the copy install.sh writes out at install time.
|
这个修复需要同时支持已有 Linux Edge 的正常升级流程,不能只在新安装或重新运行安装脚本时生效。 目前两处
请在合并前补齐:
完成这些后,才能确保已有用户通过正常升级获得 #163 的修复。 |
install.sh and install-edge.sh used to write ProtectHome=true, and a bundle upgrade only swaps the files listed in MANIFEST.txt, so an existing node kept that line through every upgrade: the log collector still could not read files under /home, which is the failure issue ongridio#163 reports. Re-assert just that directive in the pre-start upgrade hook, next to the existing group-membership re-assertion. The hook runs before every agent start, so a node converges without reinstalling and without hand-editing its unit. Only the ProtectHome line of the unit this project installs is rewritten, matching the spellings systemd reads as true; every other directive and any operator drop-in is left untouched, and a drop-in that still pins true is reported in the log instead of being overridden. The step is idempotent, preserves the unit's mode and ownership across an atomic rename, and reloads systemd best-effort so the very next start uses the migrated unit. Extend scripts/test-apply-pending-upgrade.sh to drive the real hook with a temporary unit directory plus systemctl and logger shims, covering the migration itself, idempotency, preserved operator lines, the untouched drop-in, units that must not change and a missing unit. Pointing the same assertions at the pre-migration hook fails, so the suite is a real guard rather than a syntax check.
Log collection moved from Promtail to the OpenTelemetry Contrib collector with its filelog receiver, but both ProtectHome notes still described a promtail subprocess. Name the collector that is actually started today so the reason the mount namespace matters stays traceable; the restriction on directory access is unchanged.
|
复查了最新提交
验证范围:GitHub 当前检查全部通过;隔离 Linux 容器中的 |
The ProtectHome migration cases overrode only the unit and drop-in paths, so the bundle-level runs kept the hook's defaults and pointed the migration at the host unit under the systemd system directory, and the earliest runs started before the command shims existed. On a machine that really has an edge installed, running this suite as root would rewrite that host's unit and apply a staged bundle into the real binary and library directories. Route every invocation through one isolated entry point that sets the upgrade stage, binary and library dirs, the legacy target, the unit and drop-in paths and the systemctl and logger shims, and install the shims before the first run. Bundle-level runs are pointed at a unit path that never exists, and the suite now asserts that phase reloaded nothing, created no unit, never mentioned the migration and never resolved the host unit path. Pointing one bundle run back at a real unit makes the suite fail, so the new guard is not vacuous.
Summary
#163 报的两个 bug,Bug 1 已经在主干修好了,本 PR 处理 Bug 2 以及"存量节点怎么拿到这个修复":
Bug 1(
external_labels.device_id用了 frontier 的edge_id)已由现有实现解决:internal/edgeagent/plugins/config_tunnel.go:145-150明确写了"尽管线上字段名是EdgeID,它的值是 Manager 从edge_devices(type=host)解析出的 hostdevice_id,绝不能用ONGRID_EDGE_ID顶替",并且internal/edgeagent/plugins/config_tunnel_test.go:124有断言EdgeID label = ..., want manager-resolved device_id 100。所以本 PR 不再改动这部分 —— 若你确认 Bug 1 可判定关闭,这个 PR 合入后 修复 Promtail device_id 标签与 /home 访问 (Correct Promtail device labels and /home access) #163 两条都有着落。(修复 Promtail device_id 标签与 /home 访问 (Correct Promtail device labels and /home access) #163 当时把采集器写成 Promtail;日志采集现已迁移到 otelcol-contrib 的filelogreceiver,字段名与这条结论不变。)Bug 2(本 PR 修复):edge 的 systemd 单元用
ProtectHome=true,它会在服务的 mount namespace 里用空 tmpfs 覆盖/home、/root、/run/user。logs 插件是以子进程方式拉起 otelcol-contrib(filelogreceiver) 的,它继承这个 namespace,于是/home下的路径一律不可见 —— 表现就是报告里那种"Adding target 之后永远不打开文件"的静默失效。改成
ProtectHome=read-only:真正需要的保护(agent 不能写用户主目录)完全保留,只是让这些路径重新可读,而日志采集只需要读。存量节点的升级路径(按 review 意见补齐):一键升级走的是 ADR-024 bundle,
apply-pending-upgrade.sh只按 MANIFEST.txt 换文件,从不重写/etc/systemd/system/ongrid-edge.service;升级包清单里也没有 service 文件。所以旧节点哪怕升级多次,ProtectHome=true会一直留着,本 PR 的两处模板改动只有新装/重装才生效。现在apply-pending-upgrade.sh里加了ensure_protect_home,与既有ensure_log_groups同一套路:它是ongrid-edge.service的Wants=+After=前置 oneshot,每次 agent 启动前都会跑,所以这个迁移既不需要重装、也不需要运维手工改 unit,节点只要跑过这份 bundle 之后再启动一次 agent 就会收敛(具体时序边界见下一段)。迁移的范围刻意收窄:只改这个 unit 里
ProtectHome=这一行(true|yes|on|1,按 systemd 的大小写与空格习惯匹配),其余指令与用户自己的 drop-in 一律不动;ongrid-edge.service.d/里若有 drop-in 仍然钉着true(它的优先级高于主 unit),只在日志里报出来,不替用户改他自己的文件。改完 best-effortsystemctl daemon-reload,agent 随即按新配置启动。幂等:值已经是read-only就不匹配、不重写、不 reload;unit 不存在直接返回。需要如实说明一处时序边界:跑这次升级的仍是节点上旧版的
apply-pending-upgrade.sh(新脚本是在这次运行里才被换到磁盘上的),所以装上这份 bundle 的那一次启动还不会触发迁移;迁移发生在这之后的任意一次 agent 启动前(Restart=always的重启、重启机器、下一次升级,或运维手动systemctl restart ongrid-edge),无需重装、也不需要手工改 unit。要立刻收敛就手动重启一次 edge。三处一起改:随包发布的模板
deploy/install/edge/ongrid-edge.service、install.sh安装时实际写出的那份副本,以及新增的升级前置迁移。全仓库只有这三处涉及ProtectHome(已扫过deploy/与 helm/k8s 目录)。验证
bash -n deploy/install/edge/install.sh、bash -n deploy/install/edge/install-edge.sh、bash -n deploy/install/apply-pending-upgrade.sh通过。仓库自带的两个安装器守卫脚本通过:
scripts/test-edge-installer-connectivity-guard.sh→edge installer connectivity guard: okscripts/test-edge-metrics-env.py→install.sh / install-edge.sh: metrics address install/reinstall checks passed需要说清楚这两个脚本证明的是什么:它们抽取安装脚本里的连通性判断与 env 保留代码块来执行,不会解析
[Service]单元内容,所以它们能确认的是"我没有改坏安装脚本本身",不构成对本改动的行为验证。迁移逻辑走真实升级入口验证,而不是只校验安装脚本语法:
scripts/test-apply-pending-upgrade.sh新增一段,用临时 unit 目录 +systemctl/loggershim 直接调用整个apply-pending-upgrade.sh(不是把函数抄出来单测),逐条断言:ProtectHome=true被改成read-only,而ProtectSystem=strict、LimitNOFILE=65536、Environment=ONGRID_EDGE_CUSTOM=keep-me逐字保留;ProtectHome=true原样保留,同时日志里出现"still pins ProtectHome=true"的提示;daemon-reload;紧接着再跑一次升级,unit 字节级不变且不再 reload(幂等);ProtectHome=false的 unit 与根本没有该指令的 unit 都字节不变、不 reload;ProtectHome = True(带空格、首字母大写)同样被匹配并改写;自证保护有效:把上面这段断言指向迁移前的
apply-pending-upgrade.sh,同一套测试退出码 1(改动前是红的);指向改动后的版本退出码 0。三处
ProtectHome现均为read-only,注释一致。未验证项(如实说明):
ProtectHome的真实挂载效果需要 Linux + systemd,本机是 macOS、systemd-analyze不存在,CI 对安装脚本也只有bash -n这一层。新增的自动化证明的是"迁移只改这一行、幂等、会 reload、不动用户配置",不含"/home在真机上确实变为可读且不可写"这一挂载语义(read-only是 systemd 文档里的标准取值,语义为"可读写目录改为只读挂载")。请报告人用这两条自查确认:影响面
只影响 edge 的 systemd 单元安全性配置,不涉及 Go 代码、API、
.proto、数据库、前端。对已装节点的可观察变化是:升级或重启后 unit 里的ProtectHome=一行被规范化,其余配置与 drop-in 不变。如果将来有插件确实需要写用户主目录(目前没有),需要显式加ReadWritePaths=,而不是回退到true。回滚
revert 本提交即恢复模板与安装脚本里的
ProtectHome=true,无数据迁移;已迁移过的节点把该行改回true后systemctl daemon-reload即可(迁移只在看到true|yes|on|1时才动手,回滚后的值不会被再次改写)。Fixes #163
Author confirmation