diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md new file mode 100644 index 0000000..a7e1493 --- /dev/null +++ b/TROUBLESHOOTING.md @@ -0,0 +1,34 @@ +3# Troubleshooting Kerno + +If you are experiencing issues while setting up or running Kerno, please check the common scenarios below. + +## 1. Installation & Dependencies +* **Error:** `clang: command not found` or `llvm: command not found` + * **Cause:** The required eBPF build toolchain is missing from your system. + * **Fix:** Install the necessary build dependencies: + ```bash + Note: These dependencies are only required for 'make build-ebpf'. + sudo apt-get update + sudo apt-get install clang llvm libbpf-dev bpftool + ``` + +## 2. Kernel & eBPF Errors +* **Error:** `/sys/kernel/btf not found` or `failed to load BPF program` + * **Cause:** Your current kernel version is likely older than 5.8 or lacks BPF Type Format (BTF) support. + * **Fix:** Ensure you are running a modern, managed Kubernetes distribution (EKS, GKE, AKS, etc.) or update your host kernel to 5.8+. +* Note: Kerno uses tracepoints, not kprobes. Ensure your kernel has BTF (BPF Type Format) + support enabled (available in kernels 5.8+). + * **Cause:** The kernel may have restrictions on attaching probes, or the specific tracepoint is unavailable. + * **Fix:** Verify your kernel headers are installed: `sudo apt-get install linux-headers-$(uname -r)`. + +## 3. Permissions +* **Error:** `permission denied` or `Operation not permitted` + * **Cause:** Kerno requires root-level privileges to interact with eBPF hooks in the kernel. + * **Fix:** * Always run locally with `sudo`: `sudo ./kerno doctor`. + * If running in Kubernetes, ensure your DaemonSet is configured with the necessary security capabilities: `CAP_BPF`, `CAP_PERFMON`, `CAP_SYS_PTRACE`, `CAP_NET_ADMIN`, and `CAP_DAC_READ_SEARCH`. + +## 4. Reporting New Issues +If your problem is not listed here: +1. **Check existing issues:** See if another user has reported the same error on the [GitHub Issues page](https://github.com/optiqor/kerno/issues). +2. **Gather context:** Run `uname -a` to get your kernel version and include it in your report. +3. **Open a new issue:** Provide the full error logs and a brief description of how to reproduce the problem. diff --git a/internal/doctor/render.go b/internal/doctor/render.go index 5dcc394..1a2e28c 100644 --- a/internal/doctor/render.go +++ b/internal/doctor/render.go @@ -1,4 +1,4 @@ -// Copyright 2026 Optiqor contributors +// Copyright 2025 Optiqor contributors // SPDX-License-Identifier: Apache-2.0 package doctor @@ -680,3 +680,23 @@ func (r *JSONRenderer) Render(w io.Writer, report *Report) error { } return enc.Encode(jr) } + +type MarkdownRenderer struct{} + +func (m *MarkdownRenderer) Render(w io.Writer, r *Report) error { + var sb strings.Builder + sb.WriteString("# Kerno Doctor - Diagnostic Report\n\n") + + // Iterate through findings to access Fix + for _, f := range r.Findings { + if len(f.Fix) > 0 { + sb.WriteString("**Fix:**\n") + for _, fix := range f.Fix { + sb.WriteString(fmt.Sprintf("- %s\n", fix)) + } + } + } + + _, err := w.Write([]byte(sb.String())) + return err +} diff --git a/internal/doctor/render_test.go b/internal/doctor/render_test.go index 3140ed2..dffd040 100644 --- a/internal/doctor/render_test.go +++ b/internal/doctor/render_test.go @@ -313,3 +313,23 @@ func TestJSONRenderer_EmptyFindings(t *testing.T) { t.Errorf("expected nil or empty findings, got %d", len(jr.Findings)) } } + +func TestMarkdownRenderer(t *testing.T) { + r := &Report{ + Findings: []Finding{ + {Fix: []string{"Step one", "Step two"}}, + }, + } + mr := &MarkdownRenderer{} + var sb strings.Builder + err := mr.Render(&sb, r) + + if err != nil { + t.Fatalf("Render failed: %v", err) + } + + output := sb.String() + if !strings.Contains(output, "- Step one") || !strings.Contains(output, "- Step two") { + t.Errorf("Expected markdown list output, got: %s", output) + } +}