Files
cairnobs/docs/phase-1-runbook.md
jcoffey-dev 9bbd802a91 Catch the runbooks up with the query API they describe
Phase 2 unified the two query languages behind one endpoint and renamed
the request field, and the runbooks were never updated. Following them
today does not work:

  {"sql": ...}                 -> 400 query must not be empty
  POST /api :8080/search       -> 404, the route no longer exists

Both appear in the Phase 0 and Phase 1 runbooks and in the
windows-fixture README. That matters more than a normal doc typo,
because status.md cites the Phase 0 runbook as the record of how Phase
0 was verified -- so the documented verification procedure is one
nobody can re-run as written.

The Phase 1 step is rewritten rather than search-and-replaced: it
checked the SQL and full-text paths against two different endpoints,
and its exit criterion (the same record_id from both) now has to be
expressed against /query twice, once with SQL and once with a bare
word.

Phase 0's expected output for SELECT 1 also gained a warnings field
since it was written.

Every command here was run against a live stack before being written
down, including confirming both paths return the same record_id.

Signed-off-by: John Coffey <[email protected]>
2026-09-04 17:44:54 -07:00

249 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1 runbook
Extends `/docs/phase-0-runbook.md` with Windows log collection and
full-text search. Read that one first — this assumes the Phase 0 stack
(dev certs, `docker compose up`, backend sanity check) already works;
Phase 1 layers on top of it, doesn't replace it.
## What's actually been verified vs. what needs real Windows
Unlike Phase 0's original draft, most of this runbook reflects steps
actually run in this session against a live stack, not just planned:
- **Verified for real:** the full Linux pipeline through search (agent →
ingest's `record_id` assignment → Redpanda → both consumers →
ClickHouse *and* Tantivy → both `/query` and `/search` → the same
`record_id` back from both). The `windows-fixture` generator sending
Windows-*shaped* data through the same pipeline and being correctly
queryable both ways, including `winevt.*` attributes and severity
mapping.
- **Not verified, and can't be from the environment this was built in:**
the actual Windows agent binary — `EvtSubscribe`, ETW session creation,
Windows service registration. No Windows toolchain was available
anywhere (confirmed: only the Linux target's std library installed, no
rustup, no way to even `cargo check --target x86_64-pc-windows-*`).
Part C below is the logical sequence to run on a real or virtualized
Windows host, not a report that it's been run.
## Prerequisites (beyond Phase 0's)
- A Windows host or VM (Windows 10/11 or Windows Server) for Part C.
- `mingw-w64` if cross-compiling the Windows build from Linux (optional —
building natively on Windows with `rustup target add
x86_64-pc-windows-msvc` works too and needs no extra setup on the Linux
side).
- Administrator access on the Windows host, for service registration and
(if you enable it) ETW.
## Part A: full-text search (Linux-only, no Windows needed)
Only needs what Phase 0's runbook already set up.
### A1. Bring the stack up (if not already)
```sh
docker compose up -d --build
```
Same as Phase 0, now also builds and starts `search` (Tantivy full-text
indexing). Confirm it's actually logging — same `RUST_LOG` gap the agent
has by default:
```sh
docker compose logs search
```
You should see "search gRPC server listening" and rskafka connecting to
all of `cairnobs.logs.raw`'s partitions. If you see nothing at all, check
`RUST_LOG=info` is set on the `search` service in `docker-compose.yml`.
### A2. Generate a log line and confirm both query paths agree
Follow Phase 0's runbook to get the agent running and generate a test
line (steps 46 there — mTLS certs, build, run, `logger`). Then, instead
of just checking `/query`, check both:
```sh
# The SQL path (ClickHouse).
curl -X POST http://localhost:8080/query -H 'Content-Type: application/json' \
-d '{"query": "SELECT record_id, message FROM logs ORDER BY timestamp DESC LIMIT 1"}'
# The full-text path (Tantivy). A bare word is a free-text search -- see
# /docs/query-language-reference.md. Both go to /query: Phase 2 unified
# the two languages behind one endpoint, and the separate POST /search
# this step used to call no longer exists.
curl -X POST http://localhost:8080/query -H 'Content-Type: application/json' \
-d '{"query": "<a distinctive word from your test log line>"}'
```
**The `record_id` in both responses should match.** That's the actual
Phase 1 exit criterion (`/PROJECT-SPEC.md`) for the Linux half: the same
record, reachable both ways. If `/search` returns nothing yet, give it a
few more seconds — Tantivy commits on a timer (`COMMIT_INTERVAL_MS`,
default 2s), so there's a small window where a record is in ClickHouse
but not yet searchable.
### A3. Confirm from the web UI
Open `http://localhost:3000` — there are now two pages, linked via the
top nav: **SQL Query** (unchanged from Phase 0) and **Full-Text Search**
(new). Run the same free-text term on the search page and confirm you
see the row.
## Part B: Windows-shaped data without a Windows host
Still no Windows needed — this tests the pipeline's handling of
Windows-*shaped* data, not the real Windows integration (see
`/hack/windows-fixture/README.md` for the exact distinction).
```sh
cd hack/windows-fixture
go run . --count 5
```
Then repeat A2's pattern: query for one of the synthetic events by
`attributes['winevt.event_id']` via `/query`, and by a distinctive word
from its message via `/search`. Both should return it, and `attributes`
should carry `winevt.event_id`/`winevt.provider`/`winevt.channel`/
`winevt.computer`.
## Part C: the real Windows agent (needs actual Windows)
### C1. Build
On the Windows host itself (simplest — avoids cross-compilation
entirely):
```powershell
rustup target add x86_64-pc-windows-msvc
cd agent
cargo build --release --target x86_64-pc-windows-msvc --no-default-features --features windows-eventlog,etw
```
Or cross-compile from Linux, then copy the binary over:
```sh
rustup target add x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu --no-default-features --features windows-eventlog,etw
```
`protoc` needs to be on `PATH` either way (used by `tonic-build` at
compile time), same requirement as the Linux build.
### C2. Get mTLS certs onto the Windows host
Copy `hack/dev-certs/out/{ca,client,client-key}.pem` from wherever you
ran `generate.sh` to `C:\ProgramData\CairnObsAgent\` on the Windows host
(create the directory first). Same dev-only certs Phase 0's Linux agent
uses — the CA doesn't care what platform the client is on, only that the
client cert was signed by it.
### C3. Config
Create `C:\ProgramData\CairnObsAgent\agent.toml`:
```toml
[source]
kind = "eventlog"
channels = ["Application", "System", "Security"]
[ingest]
endpoint = "https://<host-running-docker-compose>:4317"
```
If Docker Compose runs on a different machine than the Windows host,
`ingest`'s server cert SAN needs to cover that hostname/IP too — see
`hack/dev-certs/generate.sh` and regenerate with an updated SAN if
needed (same note as Phase 0's runbook's troubleshooting section).
### C4. Run it directly first, before installing as a service
```powershell
$env:RUST_LOG="info"
.\cairnobs-agent.exe --config C:\ProgramData\CairnObsAgent\agent.toml
```
Confirms the Event Log source and mTLS connection work before adding the
Windows service layer on top — if something's wrong, it's much easier to
diagnose here than after wrapping it in a service.
### C5. Generate a Windows Event Log entry and confirm it flows through
From another PowerShell window (or Event Viewer):
```powershell
eventcreate /T INFORMATION /ID 1 /L APPLICATION /SO "CairnObsTest" /D "phase1 windows verification line"
```
Then check both query paths, same pattern as A2.
### C6. Install as a service
```powershell
.\cairnobs-agent.exe install
sc.exe start CairnObsAgent
```
Verify it's running (`sc.exe query CairnObsAgent`) and generate another
test event to confirm it's still flowing through while running as a
service, not just in the foreground. **Known gap:** no console under the
SCM means `tracing`'s log output currently has nowhere to go — see
`/agent/README.md`'s "Running as a Windows service" section. If
something goes wrong here, you're debugging blind until that's
addressed; C4's foreground run is where to diagnose real problems.
```powershell
sc.exe stop CairnObsAgent
.\cairnobs-agent.exe uninstall
```
### C7 (optional). ETW
Only if you actually want it running — **read the privilege section in
`/agent/README.md` first.** ETW needs elevated privileges (an
administrator token or `SeSystemProfilePrivilege`), a real consideration
for a log-shipping agent, not a formality. Providers are configured by
GUID (`logman query providers "<Name>"` to look one up):
```toml
[source]
kind = "etw"
providers = ["{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}"]
```
### C8 (informational). WEF
No new steps — see `/agent/README.md`'s WEF section. The supported
pattern is running this same agent (Event Log source) on a Windows
Server already acting as a native Windows Event Collector, pointed at
the `ForwardedEvents` channel instead of the usual three. A true
agentless WS-Management receiver is explicitly not built in Phase 1.
## Troubleshooting (Phase 1-specific)
**`/search` returns nothing but `/query` finds the record.**
Check `COMMIT_INTERVAL_MS` hasn't elapsed yet (default 2s) — Tantivy
batches commits, same reasoning as ClickHouse batching inserts. If it's
been well over that and still nothing: `docker compose logs search`
look for "skipping record with empty record_id" (would mean something
upstream isn't assigning IDs — shouldn't happen) or connection errors to
Redpanda.
**Windows agent connects but Event Log entries never show up.**
Check the channel name is exactly right (`Application`/`System`/
`Security`, case matters to the Windows API) and that the account
running the agent has read access to that log — `Security` specifically
often needs elevated rights beyond what `Application`/`System` need.
**Windows build fails to find `protoc`.**
Same requirement as the Linux build — install `protoc` and ensure it's
on `PATH` before `cargo build`. On Windows, the official protoc release
zip plus adding its `bin/` to `PATH` is the simplest route.
**Nothing in this section covers the problem.**
Genuinely possible — this is the least-tested part of the whole Phase 1
build (see the caveat at the top). Check `/agent/README.md`'s Windows
sections for the specific module involved (`source/windows_eventlog.rs`,
`source/etw.rs`, `service.rs`) and their own "UNVERIFIED" comments for
what's most likely to need a real fix.