❯ go-clikit
v0.10.0 pkg.go.dev ↗

guides › write a doctor command

Write a doctor command

Check the machine, and write each check as a line for a person or as JSON for a script, in fixed words.

A doctor command looks at the machine and says what is wrong and what to do about it. doctor.Check holds one check: a name, a status, a detail and a remediation.

Procedure#

  1. Make a Check for each thing that you look at. Use doctor.StatusOK, doctor.StatusWarning or doctor.StatusFailed.
  2. Write the checks for a person with doctor.Write, or as JSON with cliout.WriteJSON.
  3. Pick the exit status from doctor.Worst.
const pull = "Pull the node image:\n\ndocker pull ghcr.io/gsi-hpc/sind-node"
checks := []doctor.Check{
	{Name: "Docker Engine", Status: doctor.StatusOK, Detail: "28.1.1 (>= 25.0)"},
	{Name: "node image", Status: doctor.StatusFailed, Detail: "not found\x1b[2J", Remediation: pull},
	{Name: "inotify", Status: doctor.StatusWarning, Detail: "max_user_instances 128 (optional)"},
	{Name: "sshuttle", Status: doctor.StatusWarning, Detail: "not in PATH"},
}

if err := doctor.Write(os.Stdout, checks); err != nil {
	fmt.Println(err)
}
failed, warned := doctor.Count(checks)
fmt.Printf("\n%d checks, %d failed, %d warnings\n", len(checks), failed, warned)
if doctor.Worst(checks) == doctor.StatusFailed {
	fmt.Println("exit status 1")
}
✓ Docker Engine: 28.1.1 (>= 25.0)
✗ node image: not found\x1b[2J
! inotify: max_user_instances 128 (optional)
! sshuttle: not in PATH

Pull the node image:

docker pull ghcr.io/gsi-hpc/sind-node

4 checks, 1 failed, 2 warnings
exit status 1
ExampleWrite in doctor/example_test.go. CI runs it and checks its output.
check := doctor.Check{Name: "inotify", Status: doctor.StatusWarning, Detail: "max_user_instances 128"}
out, err := json.Marshal(check)
if err != nil {
	fmt.Println(err)
}
fmt.Println(string(out))
{"name":"inotify","status":"warning","detail":"max_user_instances 128"}
ExampleCheck in doctor/example_test.go. CI runs it and checks its output.
CAUTION

Worst fails closed. A status that is none of the three words counts as failed.

The status words, the JSON keys and the text that Write writes are an interface (decision 38). A script can read them.