Re-apply the felis-api Deployment on existing installs so FELIS_SMTP_PASSWORD exists #2

Closed
opened 2026-07-28 12:20:35 +09:00 by FLYEMOJ1 · 2 comments
FLYEMOJ1 commented 2026-07-28 12:20:35 +09:00 (Migrated from github.com)

问题

SMTP 子系统(config + mail 包 + Secret + TUI 的 e 配置屏)是 2026-07-20 加进来的,felis-api 从环境变量 FELIS_SMTP_PASSWORD 取密码。全新安装没问题 —— 渲染 Deployment 时会带上这个 env var。已经部署的安装取不到它:Deployment 是在这个 env var 存在之前渲染的。

结果是邮件功能在老安装上静默失效。owner 解锁流程(SMTP → passkey → 验证邮箱)走不通,op.console 的登录会 404。

kubectl rollout restart 修不了这个 —— 它重建 Pod,但 Pod 是照着 Deployment spec 建的,spec 里没有的 env var 重启多少次也不会长出来。felis setup 也修不了:它在已部署的主机上会跳过 bootstrap(setup.go:69-74 的 hostBootstrapReady 门控),所以够不到控制面 bundle。

收敛命令

在受影响的主机上重跑装机器:

sudo bash deploy/bootstrap.sh

它是幂等的,会重渲染并 apply 整个控制面 bundle(:1982-1987),Deployment 更新后 FELIS_SMTP_PASSWORD 就在了。三个 flag 全部来自脚本内的变量,操作者不需要记住装机时用了什么参数。

密码本身仍要由 felis-smtp Secret 提供 —— env var 是 Optional: true 的 secretKeyRef,Secret 不在时 Pod 照样起,只是取不到值。

证据

Identified by Claude Opus 5 (claude-opus-5) while auditing the SMTP subsystem's deployment path on 2026-07-28.

internal/platform/workloads.go:241-253 —— 这个 env var 是无条件 append 的,和两个 S3 变量并排,没有任何配置判断:

env = append(env,
	corev1.EnvVar{Name: UploadsS3AccessKeyEnv, ...},
	corev1.EnvVar{Name: UploadsS3SecretKeyEnv, ...},
	// The [smtp] relay password, same optional-Secret pattern: absent until the
	// setup wizard's "configure email" step creates felis-smtp.
	corev1.EnvVar{Name: SMTPPasswordEnv, ValueFrom: &corev1.EnvVarSource{SecretKeyRef: ...}},
)

所以任何一次重渲染必定带上它,与配置里有没有 [smtp] 段无关。

重跑不会冲掉 TUI 写的 [smtp] 配置 —— write_felis_toml() 第一件事就是把它抠出来带走:

write_felis_toml() {
  local target="$1" db_host="$2" smtp_block
  smtp_block="$(persisted_smtp_block)"
  if [ -n "$smtp_block" ]; then
    log "carrying forward the configured [smtp] relay"

persisted_smtp_block() 依次读 ${STATE_DIR}/felis.host.toml 和 felis.pod.toml,awk 从 [smtp] 打到下一个 section header 为止。

2026-07-28 更正:这条原本写成 issue #1 的症状之一,那是归错了。FELIS_SMTP_PASSWORD 住在 felis-api 的 Deployment 上,不在 MinecraftServer CR 上,refreshDerivedEnv 的 create-if-absent 限制够不到它。收敛路径一直存在,只是没人把它写下来。

验收

kubectl get deployment felis-api -o jsonpath='{.spec.template.spec.containers[0].env[*].name}' 能看到 FELIS_SMTP_PASSWORD,且发一封测试邮件能到达。

备注

需要在集群主机上执行,我这边的工具链拿不到写权限,所以挂 help wanted。

发信路径有一个已经踩过的坑,值得在验证时留意:Fastmail 在 DATA 结束时才拒绝发件人身份。MAIL FROM 阶段它回 250,一直到 w.Close() 才报错。所以任何在 DATA 之前就停下的预检(连上了、EHLO 通了、认证过了)都会给出假绿灯。要验证就得真发一封出去。

## 问题 SMTP 子系统(config + mail 包 + Secret + TUI 的 `e` 配置屏)是 2026-07-20 加进来的,`felis-api` 从环境变量 `FELIS_SMTP_PASSWORD` 取密码。全新安装没问题 —— 渲染 Deployment 时会带上这个 env var。**已经部署的安装取不到它**:Deployment 是在这个 env var 存在之前渲染的。 结果是邮件功能在老安装上静默失效。owner 解锁流程(SMTP → passkey → 验证邮箱)走不通,op.console 的登录会 404。 `kubectl rollout restart` 修不了这个 —— 它重建 Pod,但 Pod 是照着 Deployment spec 建的,spec 里没有的 env var 重启多少次也不会长出来。`felis setup` 也修不了:它在已部署的主机上会跳过 bootstrap(`setup.go:69-74` 的 `hostBootstrapReady` 门控),所以够不到控制面 bundle。 ## 收敛命令 在受影响的主机上重跑装机器: ```sh sudo bash deploy/bootstrap.sh ``` 它是幂等的,会重渲染并 apply 整个控制面 bundle(`:1982-1987`),Deployment 更新后 `FELIS_SMTP_PASSWORD` 就在了。三个 flag 全部来自脚本内的变量,操作者不需要记住装机时用了什么参数。 密码本身仍要由 `felis-smtp` Secret 提供 —— env var 是 `Optional: true` 的 secretKeyRef,Secret 不在时 Pod 照样起,只是取不到值。 ## 证据 Identified by Claude Opus 5 (claude-opus-5) while auditing the SMTP subsystem's deployment path on 2026-07-28. `internal/platform/workloads.go:241-253` —— 这个 env var 是**无条件** append 的,和两个 S3 变量并排,没有任何配置判断: ```go env = append(env, corev1.EnvVar{Name: UploadsS3AccessKeyEnv, ...}, corev1.EnvVar{Name: UploadsS3SecretKeyEnv, ...}, // The [smtp] relay password, same optional-Secret pattern: absent until the // setup wizard's "configure email" step creates felis-smtp. corev1.EnvVar{Name: SMTPPasswordEnv, ValueFrom: &corev1.EnvVarSource{SecretKeyRef: ...}}, ) ``` 所以任何一次重渲染必定带上它,与配置里有没有 `[smtp]` 段无关。 重跑不会冲掉 TUI 写的 `[smtp]` 配置 —— `write_felis_toml()` 第一件事就是把它抠出来带走: ```sh write_felis_toml() { local target="$1" db_host="$2" smtp_block smtp_block="$(persisted_smtp_block)" if [ -n "$smtp_block" ]; then log "carrying forward the configured [smtp] relay" ``` `persisted_smtp_block()` 依次读 `${STATE_DIR}/felis.host.toml` 和 `felis.pod.toml`,awk 从 `[smtp]` 打到下一个 section header 为止。 > **2026-07-28 更正**:这条原本写成 issue #1 的症状之一,那是归错了。`FELIS_SMTP_PASSWORD` 住在 felis-api 的 **Deployment** 上,不在 MinecraftServer CR 上,`refreshDerivedEnv` 的 create-if-absent 限制够不到它。收敛路径一直存在,只是没人把它写下来。 ## 验收 `kubectl get deployment felis-api -o jsonpath='{.spec.template.spec.containers[0].env[*].name}'` 能看到 `FELIS_SMTP_PASSWORD`,且发一封测试邮件能到达。 ## 备注 需要在集群主机上执行,我这边的工具链拿不到写权限,所以挂 `help wanted`。 发信路径有一个已经踩过的坑,值得在验证时留意:**Fastmail 在 DATA 结束时才拒绝发件人身份**。`MAIL FROM` 阶段它回 250,一直到 `w.Close()` 才报错。所以任何在 DATA 之前就停下的预检(连上了、EHLO 通了、认证过了)都会给出假绿灯。要验证就得真发一封出去。
Lemon-miaow commented 2026-09-24 12:02:36 +09:00 (Migrated from github.com)

注记(老装机一次性操作,非代码缺陷——保持打开做待办跟踪):
FELIS_SMTP_PASSWORD 住在 felis-api Deployment 上,重跑 deploy/bootstrap.sh 会重渲染 Deployment 的 env(并把 felis-smtp Secret 复制到需要它的命名空间),即自动收敛。已在运行、暂不重跑安装器的机器,走 panel 的 configure email 流程同样会刷新环境(#29 修复后该路径不再被 namespace 冲突吞掉)。

注记(老装机一次性操作,非代码缺陷——保持打开做待办跟踪): `FELIS_SMTP_PASSWORD` 住在 felis-api **Deployment** 上,重跑 `deploy/bootstrap.sh` 会重渲染 Deployment 的 env(并把 felis-smtp Secret 复制到需要它的命名空间),即自动收敛。已在运行、暂不重跑安装器的机器,走 panel 的 configure email 流程同样会刷新环境(#29 修复后该路径不再被 namespace 冲突吞掉)。
Lemon-miaow commented 2026-09-26 08:43:53 +09:00 (Migrated from github.com)

收敛路径已落到文档,VM 上实测过。

  • 7c2fa08 docs/operations.md 新增 "Bringing an older install up to date":重跑装机器 → felis converge → felis converge -user-rcon,并给出三条核对命令。
  • VM 演练:先把 felis-api Deployment 里的 FELIS_SMTP_PASSWORD 删掉模拟老安装,重跑 bootstrap.sh 之后
    kubectl -n felis get deploy felis-api -o jsonpath='{...env[*].name}' 重新列出 FELIS_SMTP_PASSWORD;[smtp] 段由 write_felis_toml() 带过去。

验收的后半句(真发一封信到达)这次没做:VM 上没有配置 SMTP relay,也不往真实地址发信。env var 这一半已满足,发信验证留给配好 relay 的主机按文档最后一段执行。

收敛路径已落到文档,VM 上实测过。 - 7c2fa08 `docs/operations.md` 新增 "Bringing an older install up to date":重跑装机器 → `felis converge` → `felis converge -user-rcon`,并给出三条核对命令。 - VM 演练:先把 felis-api Deployment 里的 `FELIS_SMTP_PASSWORD` 删掉模拟老安装,重跑 `bootstrap.sh` 之后 `kubectl -n felis get deploy felis-api -o jsonpath='{...env[*].name}'` 重新列出 `FELIS_SMTP_PASSWORD`;`[smtp]` 段由 `write_felis_toml()` 带过去。 验收的后半句(真发一封信到达)这次没做:VM 上没有配置 SMTP relay,也不往真实地址发信。env var 这一半已满足,发信验证留给配好 relay 的主机按文档最后一段执行。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: FelisMC/Felis#2