fix(macos): skip common role Linux baseline on Darwin
The common role's 'Base | *' tasks (timedatectl timezone, /etc/hostname, hostname, /etc/hosts, ssh hardening, fail2ban, file limits, firewall) all run with become: true against Linux-only tooling/paths and fail on macOS — the reported timedatectl failure is just the first. Add patch_playbook_common_macos() (post-clone, Darwin-only) that appends an ansible_os_family != 'Darwin' guard to the whole Base block. Idempotent; verified against the real role; Linux unchanged. Documents TC-MAC-014.
This commit is contained in:
parent
11701c6037
commit
6607d32920
@ -117,6 +117,16 @@
|
||||
| **目录策略** | 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 行为 |
|
||||
|
||||
## TC-MAC-014: common 角色 Linux 基线(timedatectl 等)在 macOS 失败
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **触发文件** | `roles/vhosts/common/tasks/main.yml` |
|
||||
| **触发报错** | `TASK [common : Base | set timezone]` → `[Errno 2] No such file or directory: b'timedatectl'`(macOS 无 systemd 的 `timedatectl`) |
|
||||
| **根因** | `common` 角色的 `Base | *` 系列任务是 Linux 服务器基线:`timedatectl` 设时区、改写 `/etc/hostname`、`/etc/hosts`、设主机名、加固 SSH、配置 fail2ban、调文件句柄上限、放行防火墙端口。全部 `become: true` 且依赖 Linux 专有工具/路径,在 macOS(`become=false`)下会逐条失败,`set timezone` 只是第一个 |
|
||||
| **修复方案** | 经评估这些基线对 macOS 本机开发部署既不适用也无权限执行,故在 `setup-ai-workspace-all-in-one.sh` 新增 `patch_playbook_common_macos()`(同样走克隆后打补丁),仅在 Darwin 下为整个 `Base | *` 块追加 `ansible_os_family != 'Darwin'` 守卫(共 9 处:7 个任务追加 `when`,2 个已有 `when` 列表追加该条件)。`import_tasks` 的 `when` 会传播到子任务,因此 ssh 加固/fail2ban/limits/firewall 子任务一并跳过。幂等、YAML 合法、Linux 行为不变 |
|
||||
| **备注** | 用户仅点名 `set timezone`,但其后的 Base 任务会以相同原因连环失败,故一并守卫以避免逐个往返 |
|
||||
|
||||
---
|
||||
|
||||
## 修复维度总结
|
||||
@ -127,7 +137,8 @@
|
||||
| 权限收缩 (become: false) | TC-002, TC-006, TC-007, TC-008, TC-009 |
|
||||
| 用户组适配 (staff vs ubuntu) | TC-003, TC-010 |
|
||||
| 目录路径降级 ($HOME vs /home/ubuntu, /opt, /etc) | TC-004, TC-006, TC-009, TC-010, TC-012, TC-013 |
|
||||
| 克隆后补丁注入 (post-clone patch) | TC-013 |
|
||||
| 克隆后补丁注入 (post-clone patch) | TC-013, TC-014 |
|
||||
| Linux 基线整体跳过 (skip Linux baseline on Darwin) | TC-014 |
|
||||
| 包管理器绕过 (skip apt on Darwin) | TC-008, TC-010 |
|
||||
| 模板变量解耦 (remove nvm/nodejs_version) | TC-005 |
|
||||
| 路径空格兼容 (argv vs string) | TC-011 |
|
||||
|
||||
@ -117,3 +117,21 @@ failed (item=/opt/vault/data): Permission denied: b'/opt/vault'
|
||||
**验证**:`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`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 续:common 角色 Linux 基线(TC-MAC-014,19:41)
|
||||
|
||||
**进展**:vault 修复后部署推进到 161 个任务,新阻塞点为 `common : Base | set timezone`:
|
||||
|
||||
```
|
||||
fatal: timedatectl set-timezone Asia/Shanghai -> [Errno 2] No such file or directory: b'timedatectl'
|
||||
```
|
||||
|
||||
**根因**:`common` 的 `Base | *` 是 Linux 服务器基线(时区、hostname、/etc/hosts、SSH 加固、fail2ban、limits、防火墙),全部 `become: true` + Linux 专有工具/路径。`set timezone` 只是第一个,其余会连环失败。
|
||||
|
||||
**解法**:新增 `patch_playbook_common_macos()`(仍走克隆后打补丁),仅在 Darwin 下给整个 Base 块加 `ansible_os_family != 'Darwin'` 守卫(9 处)。`import_tasks` 的 `when` 自动传播到子任务,故 ssh/fail2ban/limits/firewall 一并跳过。
|
||||
|
||||
**验证**:`bash -n` 通过;用真实 `common/tasks/main.yml` 跑补丁,YAML 合法、守卫计数 9、二次执行幂等、Linux 段落(Debian/RedHat/addon)不变。
|
||||
|
||||
**说明**:用户仅点名 timezone,但为避免逐个往返,已一并守卫同源会失败的 Base 任务。
|
||||
|
||||
@ -1177,6 +1177,78 @@ macos_path.write_text(macos_text)
|
||||
PY
|
||||
}
|
||||
|
||||
# The common role's "Base | *" tasks configure a Linux server: set timezone via
|
||||
# timedatectl, rewrite /etc/hostname + /etc/hosts, set the hostname, harden ssh,
|
||||
# configure fail2ban, raise file limits and open firewall ports. All of them run
|
||||
# with become: true and target Linux-only tooling/paths, so they fail on macOS
|
||||
# (e.g. timedatectl is absent). Patch the cloned role to skip the entire Base
|
||||
# baseline on Darwin. Linux is untouched.
|
||||
patch_playbook_common_macos() {
|
||||
local main_file="roles/vhosts/common/tasks/main.yml"
|
||||
[ -f "$main_file" ] || return 0
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
path = Path("roles/vhosts/common/tasks/main.yml")
|
||||
text = path.read_text()
|
||||
guard = " when: ansible_os_family != 'Darwin'\n"
|
||||
|
||||
# Tasks that end with a trailing attribute and have no `when:` yet -> append guard.
|
||||
append_blocks = [
|
||||
('- name: Base | set timezone\n'
|
||||
' ansible.builtin.command: "timedatectl set-timezone Asia/Shanghai"\n'
|
||||
' changed_when: false\n'
|
||||
' become: true\n'),
|
||||
('- name: Base | render /etc/hostname\n'
|
||||
' ansible.builtin.template:\n'
|
||||
' src: templates/hostname.j2\n'
|
||||
' dest: /etc/hostname\n'
|
||||
' owner: root\n'
|
||||
' group: root\n'
|
||||
' mode: "0644"\n'
|
||||
' become: true\n'),
|
||||
('- name: Base | set hostname\n'
|
||||
' ansible.builtin.hostname:\n'
|
||||
' name: "{{ inventory_hostname }}"\n'
|
||||
' become: true\n'),
|
||||
('- name: Base | update /etc/hosts\n'
|
||||
' ansible.builtin.template:\n'
|
||||
' src: templates/hosts\n'
|
||||
' dest: /etc/hosts\n'
|
||||
' owner: root\n'
|
||||
' group: root\n'
|
||||
' mode: "0644"\n'
|
||||
' become: true\n'),
|
||||
('- name: Base | harden ssh\n'
|
||||
' ansible.builtin.script: files/secure_ssh.sh\n'
|
||||
' become: true\n'),
|
||||
('- name: Base | harden ssh config\n'
|
||||
' ansible.builtin.import_tasks: harden_ssh.yml\n'
|
||||
' tags: [ssh, security]\n'),
|
||||
('- name: Base | configure fail2ban\n'
|
||||
' ansible.builtin.import_tasks: fail2ban.yml\n'
|
||||
' tags: [fail2ban, security]\n'),
|
||||
]
|
||||
for block in append_blocks:
|
||||
if block in text and (block + guard) not in text:
|
||||
text = text.replace(block, block + guard, 1)
|
||||
|
||||
# Tasks that already have a `when:` list -> add the Darwin condition to it.
|
||||
when_blocks = [
|
||||
(' when:\n'
|
||||
' - common_security_limits.enabled | default(true) | bool\n'),
|
||||
(' when:\n'
|
||||
' - common_firewall.enabled | default(true) | bool\n'),
|
||||
]
|
||||
extra = " - ansible_os_family != 'Darwin'\n"
|
||||
for block in when_blocks:
|
||||
if block in text and (block + extra) not in text:
|
||||
text = text.replace(block, block + extra, 1)
|
||||
|
||||
path.write_text(text)
|
||||
PY
|
||||
}
|
||||
|
||||
ensure_core_skills_source() {
|
||||
if [ "${AI_WORKSPACE_PREFETCH_COMPLETED:-false}" = "true" ] &&
|
||||
[ -d "$XWORKSPACE_CORE_SKILLS_DIR/skills" ]; then
|
||||
@ -1958,6 +2030,7 @@ fi
|
||||
patch_playbook_user_systemd
|
||||
if [ "$(detect_os)" = "darwin" ]; then
|
||||
patch_playbook_vault_macos
|
||||
patch_playbook_common_macos
|
||||
fi
|
||||
prefetch_independent_sources
|
||||
ensure_core_skills_source
|
||||
|
||||
Loading…
Reference in New Issue
Block a user