145 lines
No EOL
6.7 KiB
Markdown
145 lines
No EOL
6.7 KiB
Markdown
# Task: Phase 2 + 3 — System Configuration and Filesystem Conversion
|
|
|
|
## Scope
|
|
|
|
Bring BigBoy from its current state (Phase 1 complete — AlmaLinux 10.2
|
|
installed and booted, all five drives mounted as xfs per the kickstart)
|
|
through Phase 2 (system configuration) and Phase 3 (converting the four
|
|
SATA drives to real btrfs). This is the task immediately before Phase 4/5
|
|
(NVIDIA driver, llama.cpp) — see `tasks/TASK-phase4-5-bringup.md` for that
|
|
separate, already-scoped task. Do not start Phase 4/5 work as part of this.
|
|
|
|
## Before starting
|
|
|
|
- Read `CLAUDE.md` at repo root if you haven't already this session.
|
|
- Read `planning/STATUS.md` for the current authoritative state of every
|
|
phase — confirm Phase 1 is actually complete before proceeding.
|
|
- Read `ansible/group_vars/bigboy.yml` for hardware facts (drive UUIDs,
|
|
by-id paths) — don't re-derive these.
|
|
- Read the existing `ansible/roles/phase-3-filesystems/tasks/main.yml` —
|
|
it currently assumes mounting *existing* btrfs volumes. It needs
|
|
updating to instead wipe and recreate the four SATA partitions as
|
|
btrfs, not just mount what's there (see Phase 3 below for why).
|
|
|
|
## Phase 2 — System Configuration
|
|
|
|
### Sudoers policy
|
|
|
|
The kickstart left a temporary, broad NOPASSWD grant in place
|
|
(`/etc/sudoers.d/00-bootstrap-<user>`) specifically so this phase would
|
|
have something to escalate privilege with. Replace it with a properly
|
|
scoped policy — this is the actual point of Phase 2, not incidental
|
|
cleanup:
|
|
|
|
- Remove `/etc/sudoers.d/00-bootstrap-<user>`.
|
|
- Deploy a real sudoers policy via a new, clearly-named file under
|
|
`/etc/sudoers.d/` (e.g. `10-admin`). Keep NOPASSWD for now — Ansible
|
|
itself still needs unattended privilege escalation to run future
|
|
phases without prompting — but this should be its own deliberate file
|
|
with its own comment explaining why, not the bootstrap file renamed.
|
|
Flag this decision in the task's output rather than silently assuming
|
|
it — if a scoped-down (password-required, or command-restricted) policy
|
|
is actually preferred, that's a decision for John, not something to
|
|
guess at here.
|
|
|
|
### SSH key deployment — single key only, this phase
|
|
|
|
Deploy **only workbench's public key** to `authorized_keys` for the admin
|
|
account. Do not add any other device's key yet — this is deliberate,
|
|
not an oversight:
|
|
|
|
```yaml
|
|
- name: Deploy workbench's SSH key
|
|
ansible.posix.authorized_key:
|
|
user: "{{ bigboy_admin_user }}"
|
|
state: present
|
|
key: "{{ lookup('file', 'keys/workbench.pub') }}"
|
|
```
|
|
|
|
The key file itself is at `ansible/keys/workbench.pub` on workbench's
|
|
local filesystem — **not committed to the repo**, deliberately. It's
|
|
listed in `.gitignore`; confirm it's actually present locally before
|
|
running this task rather than assuming, since a missing file here fails
|
|
silently different from a missing-but-tracked one (no diff will show
|
|
you it's gone). The `lookup('file', ...)` path above is relative to
|
|
wherever `ansible-playbook` is invoked from — if that's the `ansible/`
|
|
directory itself (the normal case), `keys/workbench.pub` resolves
|
|
correctly as-is; if invoked from repo root instead, adjust to
|
|
`ansible/keys/workbench.pub`.
|
|
|
|
BigBoy currently sits on the workbench bench LAN, which has no other
|
|
devices on it — additional keys (Surface, tinkerpad) get added one at a
|
|
time, tested individually, and only once BigBoy is reachable on the home
|
|
LAN. That's explicitly future work, not part of this task.
|
|
|
|
**Do not disable password authentication in this task.** That's Phase 9's
|
|
job, once key-based login is confirmed working over multiple real
|
|
sessions — this task only deploys the key, it doesn't act on it yet.
|
|
|
|
### Base system confirmation
|
|
|
|
- Confirm hostname, timezone, and NTP/chrony sync are correct.
|
|
- Confirm the repos configured by the kickstart (BaseOS, AppStream, CRB,
|
|
EPEL) are still present and reachable — `dnf repolist`.
|
|
|
|
## Phase 3 — Filesystem conversion (four SATA drives only)
|
|
|
|
**Root is explicitly out of scope for this task.** Root stays xfs,
|
|
permanently for now — there is no supported in-place xfs-to-btrfs
|
|
conversion path, and converting it would require a full reinstall
|
|
(planned separately, not before real-world testing, not part of this
|
|
playbook). Do not attempt to touch the root filesystem in any way as
|
|
part of this task.
|
|
|
|
The four SATA drives currently exist as xfs partitions (per the
|
|
kickstart, since RHEL10's Anaconda can't create btrfs at install time):
|
|
|
|
| Mount point (kickstart) | Drive | Final target |
|
|
|---|---|---|
|
|
| `/srv/backup-raw` | BACKUPDRV (Lexar 256GB) | `/srv/backup` |
|
|
| `/srv/rag-raw` | RAGLIB (Samsung EVO 500GB) | `/srv/rag-library` |
|
|
| `/srv/ai-raw` | AILOGS (Samsung EVO 250GB) | `/srv/ai-logs` |
|
|
| `/srv/prompt-raw` | PROMPTLIB (Lexar 256GB) | `/srv/prompt-library` |
|
|
|
|
For each of the four drives:
|
|
|
|
1. Unmount the existing xfs partition.
|
|
2. `mkfs.btrfs` with zstd compression.
|
|
3. Create appropriate subvolumes per the established CE storage pattern.
|
|
4. Mount at the final path (not the `-raw` staging name).
|
|
5. Update `/etc/fstab` by UUID, not by device path — same reasoning as
|
|
the kickstart's own `/dev/disk/by-id` discipline, just applied at the
|
|
filesystem-UUID level since these now have real filesystems.
|
|
6. Set appropriate mount options (`compress=zstd`, `noatime`) matching
|
|
the existing CE btrfs standard used elsewhere in the fleet.
|
|
|
|
This role should be idempotent — safe to re-run without re-wiping drives
|
|
that are already correctly converted. Check the existing filesystem type
|
|
before acting rather than assuming every run starts from raw xfs.
|
|
|
|
## Done criteria for this task
|
|
|
|
- `/etc/sudoers.d/00-bootstrap-<user>` removed, replaced by a real,
|
|
clearly-documented policy
|
|
- Workbench's SSH key present in `authorized_keys` and confirmed working
|
|
(a real login test, not just "the task ran without error")
|
|
- Password authentication still enabled (not touched — that's Phase 9)
|
|
- Hostname/timezone/NTP/repos confirmed correct
|
|
- All four SATA drives converted to btrfs, mounted at their final paths,
|
|
`/etc/fstab` updated by UUID
|
|
- Root filesystem untouched, still xfs
|
|
- `planning/STATUS.md` updated to reflect Phase 2 and 3 as complete
|
|
|
|
## Explicitly out of scope for this task
|
|
|
|
- Do not start Phase 4 (NVIDIA driver) or Phase 5 (llama.cpp) — separate,
|
|
already-scoped task in `tasks/TASK-phase4-5-bringup.md`.
|
|
- Do not disable password SSH authentication — Phase 9's job.
|
|
- Do not add Surface's or tinkerpad's SSH keys — deliberate future work,
|
|
one at a time, only once on the home LAN.
|
|
- Do not attempt any root filesystem conversion or reinstall.
|
|
- Do not build the dedicated display-monitor user (case-mounted screen
|
|
relocated from jahnet) — separately deferred, not part of this task.
|
|
- Do not build anything related to the auditable llama.cpp release
|
|
pipeline or per-client agent playbooks — both explicitly deferred per
|
|
`CLAUDE.md`. |