Repository navigation
feat(runbook): introduce runbook toolset to fetch internal runbooks #547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9282f6d
feat(runbook): introduce runbook toolset to fetch internal runbooks
mainred e759ef9
address comments
mainred 50222bd
Merge branch 'master' of github.com:robusta-dev/holmesgpt into runboo…
mainred 699fc43
Merge branch 'master' into runbook-selection
mainred File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| {% if runbooks and runbooks.catalog|length > 0 %} | ||
| # Runbook Selection | ||
|
|
||
| # Available Runbooks | ||
|
|
||
| {%- for runbook in runbooks.catalog -%} | ||
|
|
||
| description: {{ runbook.description }} | ||
| link: {{ runbook.link }} | ||
|
|
||
| {%- endfor -%} | ||
|
|
||
| ALWAYS try to find the runbooks that can provide troubleshooting instructions when the user describes an operational issue, debugging scenario, or asks for step‑by‑step troubleshooting. | ||
| To get the runbook details, use `fetch_runbook` tool by comparing the runbook description with the user prompt. | ||
| ALWAYS follow the steps described in the runbook. | ||
| If you decided not to follow one or more steps, ALWAYS explain why. | ||
| {%- endif -%} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Runbooks | ||
|
|
||
| Runbooks folder contains operational runbooks for the HolmesGPT project. Runbooks provide step-by-step instructions for common tasks, troubleshooting, and maintenance procedures related to the plugins in this directory. | ||
|
|
||
| ## Purpose | ||
|
|
||
| - Standardize operational processes | ||
| - Enable quick onboarding for new team members | ||
| - Reduce downtime by providing clear troubleshooting steps | ||
|
|
||
| ## Structure | ||
|
|
||
| ### Structured Runbook | ||
|
|
||
| Structured runbooks are designed for specific issues when conditions like issue name, id or source match, the corresponding instructions will be returned for investigation. | ||
| For example, the investigation in [kube-prometheus-stack.yaml](kube-prometheus-stack.yaml) will be returned when the issue to be investigated match either KubeSchedulerDown or KubeControllerManagerDown. | ||
| This runbook is mainly used for `holmes investigate` | ||
|
|
||
| ### Catalog | ||
|
|
||
| Catalog specified in [catalog.json](catalog.json) contains a collection of runbooks written in markdown. | ||
| During runtime, LLM will compare the runbook description with the user question and return the most matched runbook for investigation. It's possible no runbook is returned for no match. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "catalog": [ | ||
| { | ||
| "update_date": "2025-06-17", | ||
| "description": "Runbook to investigate DNS resolution issue on Kubernetes cluster", | ||
| "link": "networking/dns_troubleshooting_instructions.md" | ||
| } | ||
| ] | ||
| } |
66 changes: 66 additions & 0 deletions
66
holmes/plugins/runbooks/networking/dns_troubleshooting_instructions.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # DNS Troubleshooting Guidelines (Kubernetes) | ||
|
|
||
| ## Goal | ||
| Your primary goal when using these tools is to diagnose DNS resolution issues within a Kubernetes cluster, focusing on identifying common problems like incorrect CoreDNS/kube-dns setup, network policies, or service discovery failures by strictly following the workflow for DNS diagnosis. | ||
|
|
||
| * Use the tools to gather information about the DNS pods, services, and configuration. | ||
| * Clearly present the key findings from the tool outputs in your analysis. | ||
| * Instead of provide next steps to the user, you need to follow the troubleshoot guide to execute the steps. | ||
| * When getting pod logs, always try to get the log filter by log_filter toolset to filter out unnecessary logs by tool kubectl_logs_grep_no_match | ||
|
|
||
| ## Workflow for DNS Diagnosis | ||
|
|
||
| 1. **Check CoreDNS/kube-dns Pods:** | ||
| * Verify that the DNS pods (e.g., CoreDNS or kube-dns) are running in the `kube-system` namespace. | ||
| * Look for restarts or crashes in the DNS pods. | ||
|
|
||
| 2. **Examine DNS Service:** | ||
| * Ensure the DNS service is correctly defined: `kubectl get svc kube-dns -n kube-system` (or the equivalent for your DNS provider). | ||
| * Verify the ClusterIP of the DNS service and the ports (usually 53/UDP and 53/TCP). | ||
|
|
||
| 3. **Test DNS Resolution from a Pod:** | ||
| * Launch a debugging pod (e.g., using `busybox` or `nslookup` tools). | ||
| * **Inside the debug pod:** | ||
| * Check `/etc/resolv.conf`: | ||
| * The `nameserver` should point to the DNS service's ClusterIP. | ||
| * The `search` path should be appropriate for your namespaces (e.g., `your-namespace.svc.cluster.local svc.cluster.local cluster.local`). | ||
| * The `options` (like `ndots:5`) can affect resolution behavior. | ||
| * Attempt to resolve internal cluster names: | ||
| * A service in the same namespace (e.g., `myservice`). | ||
| * A service in a different namespace (e.g., `myservice.othernamespace`). | ||
| * A fully qualified domain name (FQDN) (e.g., `myservice.othernamespace.svc.cluster.local`). | ||
| * Attempt to resolve external names (e.g., `www.google.com`). | ||
| * Use tools like `nslookup <hostname>` or `dig <hostname>` for detailed query information. | ||
|
|
||
| 4. **Check NetworkPolicies:** | ||
| * If NetworkPolicies are in place, ensure they allow DNS traffic (to port 53 UDP/TCP) from your application pods to the DNS pods/service. | ||
| * List NetworkPolicies and Examine policies that might be affecting the source or destination pods. | ||
|
|
||
| 5. **Review CoreDNS Configuration (if applicable):** | ||
| * Inspect the CoreDNS ConfigMap: `kubectl get configmap coredns -n kube-system -o yaml`. | ||
| * Look for errors or misconfigurations in the Corefile (e.g., incorrect upstream resolvers, plugin issues). | ||
| * Inspect the customized CoreDNS ConfigMap: `kubectl get configmap coredns-custom -n kube-system -o yaml`. | ||
| * Look for errors or misconfigurations in the customizated CoreDNS config (e.g., incorrect upstream resolvers, plugin issues). | ||
|
|
||
| 6. **Check the DNS trace** | ||
| * Use findings from the DNS trace to pinpoint where DNS resolution is failing (e.g., query not reaching DNS server, invalid FQDN, or error response from DNS server). | ||
| * DNS Server should always respond to the requests from the client. Valid FQDN should return NOERROR, and invalid FQDN should return NXDOMAIN | ||
|
|
||
| ## Synthesize Findings | ||
| Based on the outputs from the above steps, describe the DNS issue clearly. For example: | ||
| * "DNS resolution for internal service 'myservice' is failing from pods in namespace 'app-ns'. The CoreDNS pods in `kube-system` are running but show 'connection refused' errors in their logs when trying to reach upstream resolvers." | ||
| * "Pods in namespace 'secure-ns' cannot resolve any hostnames. `/etc/resolv.conf` in these pods is missing the correct `nameserver` entry. This is likely due to a misconfiguration in the pod's `dnsPolicy` or the underlying node's DNS setup." | ||
| * "External DNS resolution is failing cluster-wide. The CoreDNS ConfigMap shows that the `forward` plugin is pointing to an incorrect upstream DNS server IP address." | ||
| * "DNS lookups for 'service-a.namespace-b' are timing out. A NetworkPolicy in 'namespace-b' is blocking egress traffic on port 53 to the kube-dns service." | ||
|
|
||
| ## Recommend Remediation Steps (Based on Docs) | ||
| * **CRITICAL:** ALWAYS refer to the official Kubernetes DNS debugging guide for detailed troubleshooting and solutions: | ||
| * Main guide: https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/ | ||
| * CoreDNS specific: https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/ (for CoreDNS customization which might be relevant) | ||
| * **DO NOT invent recovery procedures.** Your role is to diagnose and *point* to the correct documentation or standard procedures. | ||
| * Based on the findings, suggest which sections of the documentation are most relevant. | ||
| * If DNS pods are not running, guide towards checking pod deployment and node health. | ||
| * If `/etc/resolv.conf` is incorrect, point to sections on Pod `dnsPolicy` and `dnsConfig`. | ||
| * If NetworkPolicies are suspected, suggest reviewing policy definitions to allow DNS. | ||
| * If CoreDNS configuration seems problematic, refer to CoreDNS documentation and the Kubernetes guide on customizing it. | ||
| * If upstream DNS resolution is failing, suggest checking the upstream DNS servers and CoreDNS forward configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import logging | ||
| from typing import Any, Dict | ||
|
|
||
| from holmes.core.tools import ( | ||
| StructuredToolResult, | ||
| Tool, | ||
| ToolParameter, | ||
| ToolResultStatus, | ||
| Toolset, | ||
| ToolsetTag, | ||
| ) | ||
| from holmes.plugins.runbooks import get_runbook_by_path | ||
|
|
||
|
|
||
| # TODO(mainred): currently we support fetch runbooks hosted internally, in the future we may want to support fetching | ||
| # runbooks from external sources as well. | ||
| class RunbookFetcher(Tool): | ||
| toolset: "RunbookToolset" | ||
|
|
||
| def __init__(self, toolset: "RunbookToolset"): | ||
| super().__init__( | ||
| name="fetch_runbook", | ||
| description="Get runbook content by runbook link. Use this to get troubleshooting steps for incidents", | ||
| parameters={ | ||
| # use link as a more generic term for runbook path, considering we may have external links in the future | ||
| "link": ToolParameter( | ||
| description="The link to the runbook", | ||
| type="string", | ||
| required=True, | ||
| ), | ||
| }, | ||
| toolset=toolset, # type: ignore | ||
| ) | ||
|
|
||
| def _invoke(self, params: Any) -> StructuredToolResult: | ||
| path: str = params["link"] | ||
|
|
||
| runbook_path = get_runbook_by_path(path) | ||
| try: | ||
| with open(runbook_path, "r") as file: | ||
| content = file.read() | ||
| return StructuredToolResult( | ||
| status=ToolResultStatus.SUCCESS, | ||
| data=content, | ||
| params=params, | ||
| ) | ||
| except Exception as e: | ||
| err_msg = f"Failed to read runbook {runbook_path}: {str(e)}" | ||
| logging.error(err_msg) | ||
| return StructuredToolResult( | ||
| status=ToolResultStatus.ERROR, | ||
| error=err_msg, | ||
| params=params, | ||
| ) | ||
|
|
||
| def get_parameterized_one_liner(self, params) -> str: | ||
| path: str = params["link"] | ||
| return f"fetched runbook {path}" | ||
|
|
||
|
|
||
| class RunbookToolset(Toolset): | ||
| def __init__(self): | ||
| super().__init__( | ||
| name="runbook", | ||
| description="Fetch runbooks", | ||
| icon_url="https://platform.robusta.dev/demos/runbook.svg", | ||
| tools=[ | ||
| RunbookFetcher(self), | ||
| ], | ||
| docs_url="https://docs.robusta.dev/master/configuration/holmesgpt/toolsets/runbook.html", | ||
| tags=[ | ||
| ToolsetTag.CORE, | ||
| ], | ||
| is_default=True, | ||
| ) | ||
|
|
||
| def get_example_config(self) -> Dict[str, Any]: | ||
| return {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.