fix(macos): patch vault role post-clone for macOS-standard dirs
The vault role's 'Ensure standalone Vault directories exist' task creates /etc/vault.d and /opt/vault/data with owner: root and lacks the Darwin guard its sibling tasks have, so it fails under macOS become=false. Unlike the bridge dir (owned by the service user, fixable via -e), this owner: root is hardcoded and not overridable, so the role logic must change. Since the role lives in a separate playbooks repo, reuse the existing post-clone patch mechanism (cf. patch_playbook_user_systemd): add patch_playbook_vault_macos() that, on Darwin only, guards the directory task, makes vault dirs/binary OS-conditional (macOS -> ~/Library/Application Support/vault[/data], /opt/homebrew/bin/vault; Linux unchanged), and creates the user-owned data dir in macos.yml. Idempotent; verified against the real role. Documents TC-MAC-013.
This commit is contained in:
parent
470e5163f5
commit
11701c6037
@ -107,6 +107,16 @@
|
||||
| **修复方案** | 双层:①`setup-ai-workspace-all-in-one.sh` 的 Darwin 分支注入 `-e xworkmate_bridge_base_dir="$HOME/Library/Application Support/cloud-neutral/xworkmate-bridge"`(`curl \| bash` 拉取的是本仓库脚本,playbooks 来自独立仓库,故脚本侧 `-e` 是该路径下唯一可生效的修复点);②role `defaults/main.yml` 将默认值改为按 `ansible_os_family` 的三元表达式,使离线/本地 playbook 路径亦正确 |
|
||||
| **生效前提** | `curl \| bash` 从 GitHub `main` 拉取脚本,修复必须先 push 到 `ai-workspace-lab/xworkspace-console` 的 `main`;否则远端仍是旧脚本(extra-vars 优先级最高,若 `-e` 已执行则绝不会回落到 `/opt`,由此可判定执行的是未修复的远端脚本) |
|
||||
|
||||
## TC-MAC-013: Vault standalone 目录写入系统路径被拒
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/vault/tasks/main.yml`、`roles/vhosts/vault/vars/main.yml`、`roles/vhosts/vault/tasks/macos.yml` |
|
||||
| **触发报错** | `TASK [roles/vhosts/vault/ : Ensure standalone Vault directories exist]` → `[Errno 13] Permission denied: b'/etc/vault.d'`、`b'/opt/vault'` |
|
||||
| **根因** | “Ensure standalone Vault directories exist” 任务以 `owner: root` 创建 `/etc/vault.d` 与 `/opt/vault/data`,且**缺失** vault 角色其余 standalone 任务都带的 `ansible_os_family != 'Darwin'` 守卫。macOS 以 `become=false` 运行,既无权写 `/etc`、`/opt`,`owner: root` 的 chown 也无法完成。与 bridge 不同(其目录 owner 为服务用户,可由 `-e` 修复),该任务的 `owner: root` 为硬编码,无法用 extra-vars 覆盖,必须改 role 逻辑 |
|
||||
| **目录策略** | Linux 保持 `/etc/vault.d`、`/opt/vault/data`;macOS 改用 Apple 标准 `~/Library/Application Support/vault`、`~/Library/Application Support/vault/data`;二进制路径 macOS 取 `/opt/homebrew/bin/vault`(brew 安装位置),免去需 sudo 的 `/usr/local/bin` 软链依赖 |
|
||||
| **修复方案** | role 位于独立 playbooks 仓库,无法从本仓库直接提交;沿用脚本既有的“克隆后打补丁”机制(参见 `patch_playbook_user_systemd`),在 `setup-ai-workspace-all-in-one.sh` 新增 `patch_playbook_vault_macos()`,仅在 Darwin 下对克隆出的 vault 角色:①给目录创建任务追加 `ansible_os_family != 'Darwin'` 守卫;②把 `vault_config_dir`/`vault_data_dir`/`vault_binary_path` 改为按 OS 的三元表达式;③在 `macos.yml` 前置创建用户属主的数据目录(含 launchd 日志目录 `~/.local/state/xworkspace`)。该补丁对 `curl \| bash` 与本地执行两条路径均生效,幂等,且不改动 Linux 行为 |
|
||||
|
||||
---
|
||||
|
||||
## 修复维度总结
|
||||
@ -116,7 +126,8 @@
|
||||
| 组件获取方式替换 (brew vs binary) | TC-001 |
|
||||
| 权限收缩 (become: false) | TC-002, TC-006, TC-007, TC-008, TC-009 |
|
||||
| 用户组适配 (staff vs ubuntu) | TC-003, TC-010 |
|
||||
| 目录路径降级 ($HOME vs /home/ubuntu, /opt) | TC-004, TC-006, TC-009, TC-010, TC-012 |
|
||||
| 目录路径降级 ($HOME vs /home/ubuntu, /opt, /etc) | TC-004, TC-006, TC-009, TC-010, TC-012, TC-013 |
|
||||
| 克隆后补丁注入 (post-clone patch) | TC-013 |
|
||||
| 包管理器绕过 (skip apt on Darwin) | TC-008, TC-010 |
|
||||
| 模板变量解耦 (remove nvm/nodejs_version) | TC-005 |
|
||||
| 路径空格兼容 (argv vs string) | TC-011 |
|
||||
|
||||
@ -90,3 +90,30 @@ curl -sfL https://raw.githubusercontent.com/ai-workspace-lab/xworkspace-console/
|
||||
```
|
||||
|
||||
> 注:方式 A 走 `curl | bash` 之外的本地执行路径,脚本侧 `-e` 覆盖会直接生效;role 默认的三元表达式则覆盖离线 `PLAYBOOK_DIR` 场景。
|
||||
|
||||
---
|
||||
|
||||
## 8. 续:vault 角色阻塞(TC-MAC-013,19:24)
|
||||
|
||||
**进展**:bridge 修复生效后,部署从 145 → 154 个任务,新的阻塞点为 vault:
|
||||
|
||||
```
|
||||
TASK [roles/vhosts/vault/ : Ensure standalone Vault directories exist]
|
||||
failed (item=/etc/vault.d): Permission denied: b'/etc/vault.d'
|
||||
failed (item=/opt/vault/data): Permission denied: b'/opt/vault'
|
||||
```
|
||||
|
||||
**根因**:该目录创建任务以 `owner: root` 建 `/etc/vault.d`、`/opt/vault/data`,且缺失 vault 其余 standalone 任务都有的 `ansible_os_family != 'Darwin'` 守卫。`become=false` 下既无权写 `/etc`、`/opt`,`owner: root` 也无法 chown。
|
||||
|
||||
**与 bridge 的关键差异**:bridge 目录 owner 是服务用户(macOS 即当前用户),故可用脚本 `-e xworkmate_bridge_base_dir=...` 修复;vault 这里的 `owner: root` 是**硬编码**,extra-vars 无法覆盖,必须改 role 逻辑。而 role 在独立 playbooks 仓库,不在本仓库。
|
||||
|
||||
**解法(仍落在本仓库、对 `curl|bash` 与本地执行都生效)**:复用脚本既有的“克隆后打补丁”机制(`patch_playbook_user_systemd` 已有先例),新增 `patch_playbook_vault_macos()`,仅在 Darwin 下对克隆出的 vault 角色:
|
||||
1. 给“Ensure standalone Vault directories exist”追加 `ansible_os_family != 'Darwin'` 守卫;
|
||||
2. `vault_config_dir`/`vault_data_dir`/`vault_binary_path` 改为按 OS 的三元表达式(Linux 不变;macOS 用 `~/Library/Application Support/vault[/data]` 与 `/opt/homebrew/bin/vault`);
|
||||
3. `macos.yml` 前置创建用户属主的数据目录(含 launchd 日志目录 `~/.local/state/xworkspace`)。
|
||||
|
||||
**目录策略(按用户确认)**:Linux → `/opt/vault/data`;macOS → `~/Library/Application Support/vault/data`。
|
||||
|
||||
**验证**:`bash -n` 通过;用真实 vault 角色副本跑补丁,YAML 合法、Darwin 守卫计数 5→6、二次执行幂等、Linux 渲染仍为原系统路径、macOS 渲染为 Apple 标准路径。
|
||||
|
||||
**注意(运行方式)**:上一轮 `bash scripts/setup-...sh | bash -` 的管道是错误用法(会把脚本日志再喂给第二个 bash)。本地执行应去掉管道:`bash scripts/setup-ai-workspace-all-in-one.sh`。
|
||||
|
||||
@ -1110,6 +1110,73 @@ if updated != text:
|
||||
PY
|
||||
}
|
||||
|
||||
# On macOS the vault role's "Ensure standalone Vault directories exist" task
|
||||
# targets /etc/vault.d and /opt/vault/data with owner: root. Those paths are not
|
||||
# writable under become=false and are non-standard for macOS, so patch the
|
||||
# cloned role to: (1) skip that root-owned directory task on Darwin, (2) point
|
||||
# the vault dirs/binary at Apple-standard, user-writable locations, and (3)
|
||||
# create the data dir (user-owned) in the macОS task path. Linux is untouched.
|
||||
patch_playbook_vault_macos() {
|
||||
local vars_file="roles/vhosts/vault/vars/main.yml"
|
||||
local tasks_file="roles/vhosts/vault/tasks/main.yml"
|
||||
local macos_file="roles/vhosts/vault/tasks/macos.yml"
|
||||
[ -f "$vars_file" ] && [ -f "$tasks_file" ] && [ -f "$macos_file" ] || return 0
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
vars_path = Path("roles/vhosts/vault/vars/main.yml")
|
||||
tasks_path = Path("roles/vhosts/vault/tasks/main.yml")
|
||||
macos_path = Path("roles/vhosts/vault/tasks/macos.yml")
|
||||
|
||||
# 1) Make vault dirs and binary path OS-conditional (Linux unchanged).
|
||||
vars_text = vars_path.read_text()
|
||||
vars_subs = {
|
||||
"vault_binary_path: /usr/local/bin/vault":
|
||||
"vault_binary_path: \"{{ '/opt/homebrew/bin/vault' if ansible_os_family == 'Darwin' else '/usr/local/bin/vault' }}\"",
|
||||
"vault_config_dir: /etc/vault.d":
|
||||
"vault_config_dir: \"{{ (ansible_env.HOME ~ '/Library/Application Support/vault') if ansible_os_family == 'Darwin' else '/etc/vault.d' }}\"",
|
||||
"vault_data_dir: /opt/vault/data":
|
||||
"vault_data_dir: \"{{ (ansible_env.HOME ~ '/Library/Application Support/vault/data') if ansible_os_family == 'Darwin' else '/opt/vault/data' }}\"",
|
||||
}
|
||||
for old, new in vars_subs.items():
|
||||
if old in vars_text:
|
||||
vars_text = vars_text.replace(old, new)
|
||||
vars_path.write_text(vars_text)
|
||||
|
||||
# 2) Skip the root-owned directory creation task on macOS.
|
||||
tasks_text = tasks_path.read_text()
|
||||
dir_when_old = (
|
||||
' loop:\n'
|
||||
' - "{{ vault_config_dir }}"\n'
|
||||
' - "{{ vault_data_dir }}"\n'
|
||||
' when:\n'
|
||||
' - vault_deploy_mode == "standalone"\n'
|
||||
)
|
||||
dir_when_new = dir_when_old + " - ansible_os_family != 'Darwin'\n"
|
||||
if dir_when_old in tasks_text and " - ansible_os_family != 'Darwin'\n\n- name: Deploy standalone Vault systemd" not in tasks_text:
|
||||
tasks_text = tasks_text.replace(dir_when_old, dir_when_new, 1)
|
||||
tasks_path.write_text(tasks_text)
|
||||
|
||||
# 3) Create the macOS vault dirs (user-owned) before the launchd plist is laid down.
|
||||
macos_text = macos_path.read_text()
|
||||
dir_task = (
|
||||
"- name: Ensure macOS Vault directories exist\n"
|
||||
" ansible.builtin.file:\n"
|
||||
" path: \"{{ item }}\"\n"
|
||||
" state: directory\n"
|
||||
" mode: \"0755\"\n"
|
||||
" loop:\n"
|
||||
" - \"{{ vault_config_dir }}\"\n"
|
||||
" - \"{{ vault_data_dir }}\"\n"
|
||||
" - \"{{ ansible_env.HOME }}/.local/state/xworkspace\"\n\n"
|
||||
)
|
||||
anchor = "- name: Install HashiCorp Tap\n"
|
||||
if "Ensure macOS Vault directories exist" not in macos_text and anchor in macos_text:
|
||||
macos_text = macos_text.replace(anchor, dir_task + anchor, 1)
|
||||
macos_path.write_text(macos_text)
|
||||
PY
|
||||
}
|
||||
|
||||
ensure_core_skills_source() {
|
||||
if [ "${AI_WORKSPACE_PREFETCH_COMPLETED:-false}" = "true" ] &&
|
||||
[ -d "$XWORKSPACE_CORE_SKILLS_DIR/skills" ]; then
|
||||
@ -1889,6 +1956,9 @@ else
|
||||
fi
|
||||
|
||||
patch_playbook_user_systemd
|
||||
if [ "$(detect_os)" = "darwin" ]; then
|
||||
patch_playbook_vault_macos
|
||||
fi
|
||||
prefetch_independent_sources
|
||||
ensure_core_skills_source
|
||||
ensure_xworkmate_bridge_source
|
||||
|
||||
Loading…
Reference in New Issue
Block a user