This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Ansible playbook for installing, upgrading, and monitoring the Perforce Helix Core Server Deployment Package (SDP). README.md is the user-facing reference for variables, server types, secrets handling, and the helper-script catalog — consult it before adding new variables or roles.
The workspace is at //guest/russell_jackson/ansible-sdp/. Files on disk are read-only until opened with p4 edit. To commit:
p4 edit <existing-files>
p4 add <new-files>
p4 submit -d "message"
p4 status reports files needing reconcile. Do not reflexively run git — there is no git remote.
Every helper script wraps the same ansible-playbook main-playbook.yml --extra-vars '{"<flag>":true}' --vault-password-file password.txt --limit $1 invocation. The script name maps 1:1 to a single flow-control flag (install.sh → install_perforce, upgrade.sh → update_perforce, sudo.sh → update_sudo, etc. — see README). Targets are server or group names from inventories/p4-sdp-install.yml. Always run ./ping.sh <target> first for a connectivity check.
main-playbook.yml is intentionally bifurcated:
perforce-sdp-install role when install_perforce: true. The role's tasks/main.yml includes dependencies.yml (if update_dependencies), then install.yml (if new_sdp), then cron.yml unconditionally, then drops the replica SSH key. So ./install.sh is heavyweight and idempotent.import_role tasks_from: <name> to surgically run a single task file (update.yml, dependencies.yml, cron.yml, sudo.yml, cert.yml) gated by its own update_* flag. The non-install.sh helper scripts go through this path.When adding a new operation, decide which phase it belongs in. New "full install" steps go in the role; new "surgical update" operations get their own task file + flow flag + helper script.
roles/perforce-sdp-install/defaults/main.yml — package lists, clean commands, defaults like install_broker: false.inventories/group_vars/central/main.yml — fleet-wide: Perforce version, admin user, domain, commit_dns, install_broker: true. Its own header notes that vars here cannot be overridden by group vars elsewhere — only by host_vars.inventories/host_vars/<hostname>.yml — per-server: DNS name, perforce_server_type, volume paths, and any per-host connection overrides (ansible_user, ansible_ssh_private_key_file, ansible_become).--extra-vars from the helper scripts — flow flags only.ansible.cfg defines a fleet-wide remote_user and private_key_file; one-off hosts (e.g. AWS test boxes with a .pem) override these in their host_vars rather than editing ansible.cfg.
perforce_online_metadata_volume: "mnt/p4meta" — no leading slash. The role adds the slash. The directories must already exist (mounted EBS, NFS, or plain dirs for test rigs) — the role does not create them.roles/perforce-sdp-install/files/ (perforce-license, certificate.txt, privatekey.txt, id_rsa) are committed dummies. For test hosts, set copy_license: false and install_broker: false in host_vars so the install doesn't try to use them. Real values must be dropped in for any real deployment.id_rsa is supposed to be vault-encrypted per README, but in this checkout it's plaintext. tasks/main.yml copies it with decrypt: yes, which is a no-op on unencrypted content so the install works either way. If you re-encrypt it, the existing password.txt must decrypt it.perforce_server_type drives cron content. cron.yml selects job sets by type (p4d_master, p4d_edge, p4d_replica, p4d_standby, p4d_edgerep, p4broker, p4proxy). Picking the wrong type silently installs the wrong maintenance jobs./etc/sysctl.conf. The sysctl tuning block writes to /etc/sysctl.d/99-perforce.conf (drop-in) and restart_sysctl runs sysctl --system. Follow the same drop-in pattern for any new system-tuning tasks.Cmnd_Alias (see templates/sudoers_perforce_user.j2) — modern sudo rejects * in command arguments, so enumerate full commands explicitly and validate via visudo -cf in the task's validate:.install.sh is idempotent. When a task fails mid-run, fix the task and re-run the same script — earlier steps will be no-ops or skip cleanly.# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
Ansible playbook for installing, upgrading, and monitoring the Perforce Helix Core Server Deployment Package (SDP). `README.md` is the user-facing reference for variables, server types, secrets handling, and the helper-script catalog — consult it before adding new variables or roles.
## This repo is in Perforce, not git
The workspace is at `//guest/russell_jackson/ansible-sdp/`. Files on disk are read-only until opened with `p4 edit`. To commit:
```
p4 edit <existing-files>
p4 add <new-files>
p4 submit -d "message"
```
`p4 status` reports files needing reconcile. Do not reflexively run `git` — there is no git remote.
## Run convention
Every helper script wraps the same `ansible-playbook main-playbook.yml --extra-vars '{"<flag>":true}' --vault-password-file password.txt --limit $1` invocation. The script name maps 1:1 to a single flow-control flag (`install.sh` → `install_perforce`, `upgrade.sh` → `update_perforce`, `sudo.sh` → `update_sudo`, etc. — see README). Targets are server or group names from `inventories/p4-sdp-install.yml`. Always run `./ping.sh <target>` first for a connectivity check.
## Architecture — two-phase playbook
`main-playbook.yml` is intentionally bifurcated:
1. **Roles section** — runs the entire `perforce-sdp-install` role when `install_perforce: true`. The role's `tasks/main.yml` includes `dependencies.yml` (if `update_dependencies`), then `install.yml` (if `new_sdp`), then `cron.yml` unconditionally, then drops the replica SSH key. So `./install.sh` is heavyweight and idempotent.
2. **Tasks section** — uses `import_role tasks_from: <name>` to surgically run a single task file (`update.yml`, `dependencies.yml`, `cron.yml`, `sudo.yml`, `cert.yml`) gated by its own `update_*` flag. The non-`install.sh` helper scripts go through this path.
When adding a new operation, decide which phase it belongs in. New "full install" steps go in the role; new "surgical update" operations get their own task file + flow flag + helper script.
## Variable layering (lowest to highest precedence)
1. `roles/perforce-sdp-install/defaults/main.yml` — package lists, clean commands, defaults like `install_broker: false`.
2. `inventories/group_vars/central/main.yml` — fleet-wide: Perforce version, admin user, domain, `commit_dns`, `install_broker: true`. Its own header notes that vars here cannot be overridden by *group* vars elsewhere — only by host_vars.
3. `inventories/host_vars/<hostname>.yml` — per-server: DNS name, `perforce_server_type`, volume paths, and any per-host connection overrides (`ansible_user`, `ansible_ssh_private_key_file`, `ansible_become`).
4. `--extra-vars` from the helper scripts — flow flags only.
`ansible.cfg` defines a fleet-wide `remote_user` and `private_key_file`; one-off hosts (e.g. AWS test boxes with a `.pem`) override these in their host_vars rather than editing `ansible.cfg`.
## Things that bite
- **Volume vars are path *fragments*, not paths.** `perforce_online_metadata_volume: "mnt/p4meta"` — no leading slash. The role adds the slash. The directories must already exist (mounted EBS, NFS, or plain dirs for test rigs) — the role does not create them.
- **Placeholder files in `roles/perforce-sdp-install/files/`** (`perforce-license`, `certificate.txt`, `privatekey.txt`, `id_rsa`) are committed dummies. For test hosts, set `copy_license: false` and `install_broker: false` in host_vars so the install doesn't try to use them. Real values must be dropped in for any real deployment.
- **`id_rsa` is supposed to be vault-encrypted** per README, but in this checkout it's plaintext. `tasks/main.yml` copies it with `decrypt: yes`, which is a no-op on unencrypted content so the install works either way. If you re-encrypt it, the existing `password.txt` must decrypt it.
- **`perforce_server_type` drives cron content.** `cron.yml` selects job sets by type (`p4d_master`, `p4d_edge`, `p4d_replica`, `p4d_standby`, `p4d_edgerep`, `p4broker`, `p4proxy`). Picking the wrong type silently installs the wrong maintenance jobs.
- **Ubuntu 26.04+ has no `/etc/sysctl.conf`.** The sysctl tuning block writes to `/etc/sysctl.d/99-perforce.conf` (drop-in) and `restart_sysctl` runs `sysctl --system`. Follow the same drop-in pattern for any new system-tuning tasks.
- **Sudoers files use a `Cmnd_Alias`** (see `templates/sudoers_perforce_user.j2`) — modern sudo rejects `*` in command arguments, so enumerate full commands explicitly and validate via `visudo -cf` in the task's `validate:`.
- **`install.sh` is idempotent.** When a task fails mid-run, fix the task and re-run the same script — earlier steps will be no-ops or skip cleanly.
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 32704 | Russell C. Jackson (Rusty) |
Add CLAUDE.md with guidance for AI coding assistants. Complements README.md by documenting: this repo is in Perforce (not git), the two-phase main-playbook architecture (role vs tasks_from), variable layering precedence, and gotchas (volume path fragments, placeholder files, plaintext id_rsa, Ubuntu 26.04 sysctl drop-in, sudoers Cmnd_Alias). |