Skip to content

Commit 6c573f3

Browse files
samuelmasuyopencode
andauthored
feat(kubernetes): add support for previousPod container logs (#256)
Add 'previous' parameter to pods_log tool to retrieve logs from terminated containers, equivalent to kubectl logs --previous functionality. This enables debugging of containers that have restarted due to crashes or updates. Signed-off-by: Samuel Masuy <[email protected]> Co-authored-by: opencode <[email protected]>
1 parent 10c82f7 commit 6c573f3

File tree

4 files changed

+41
-2
lines changed

4 files changed

+41
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ Get the logs of a Kubernetes Pod in the current or provided namespace with the p
317317
- Namespace to get the Pod logs from
318318
- `container` (`string`, optional)
319319
- Name of the Pod container to get logs from
320+
- `previous` (`boolean`, optional)
321+
- Return previous terminated container logs
320322

321323
### `pods_run`
322324

pkg/kubernetes/pods.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (k *Kubernetes) PodsDelete(ctx context.Context, namespace, name string) (st
9292
k.ResourcesDelete(ctx, &schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, namespace, name)
9393
}
9494

95-
func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string) (string, error) {
95+
func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string, previous bool) (string, error) {
9696
tailLines := int64(256)
9797
pods, err := k.manager.accessControlClientSet.Pods(k.NamespaceOrDefault(namespace))
9898
if err != nil {
@@ -101,6 +101,7 @@ func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container str
101101
req := pods.GetLogs(name, &v1.PodLogOptions{
102102
TailLines: &tailLines,
103103
Container: container,
104+
Previous: previous,
104105
})
105106
res := req.Do(ctx)
106107
if res.Error() != nil {

pkg/mcp/pods.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func (s *Server) initPods() []server.ServerTool {
9999
mcp.WithString("namespace", mcp.Description("Namespace to get the Pod logs from")),
100100
mcp.WithString("name", mcp.Description("Name of the Pod to get the logs from"), mcp.Required()),
101101
mcp.WithString("container", mcp.Description("Name of the Pod container to get the logs from (Optional)")),
102+
mcp.WithBoolean("previous", mcp.Description("Return previous terminated container logs (Optional)")),
102103
// Tool annotations
103104
mcp.WithTitleAnnotation("Pods: Log"),
104105
mcp.WithReadOnlyHintAnnotation(true),
@@ -284,11 +285,16 @@ func (s *Server) podsLog(ctx context.Context, ctr mcp.CallToolRequest) (*mcp.Cal
284285
if container == nil {
285286
container = ""
286287
}
288+
previous := ctr.GetArguments()["previous"]
289+
var previousBool bool
290+
if previous != nil {
291+
previousBool = previous.(bool)
292+
}
287293
derived, err := s.k.Derived(ctx)
288294
if err != nil {
289295
return nil, err
290296
}
291-
ret, err := derived.PodsLog(ctx, ns.(string), name.(string), container.(string))
297+
ret, err := derived.PodsLog(ctx, ns.(string), name.(string), container.(string), previousBool)
292298
if err != nil {
293299
return NewTextResult("", fmt.Errorf("failed to get pod %s log in namespace %s: %v", name, ns, err)), nil
294300
} else if ret == "" {

pkg/mcp/pods_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,36 @@ func TestPodsLog(t *testing.T) {
719719
return
720720
}
721721
})
722+
podsPreviousLogInNamespace, err := c.callTool("pods_log", map[string]interface{}{
723+
"namespace": "ns-1",
724+
"name": "a-pod-in-ns-1",
725+
"previous": true,
726+
})
727+
t.Run("pods_log with previous=true returns previous pod log", func(t *testing.T) {
728+
if err != nil {
729+
t.Fatalf("call tool failed %v", err)
730+
return
731+
}
732+
if podsPreviousLogInNamespace.IsError {
733+
t.Fatalf("call tool failed")
734+
return
735+
}
736+
})
737+
podsPreviousLogFalse, err := c.callTool("pods_log", map[string]interface{}{
738+
"namespace": "ns-1",
739+
"name": "a-pod-in-ns-1",
740+
"previous": false,
741+
})
742+
t.Run("pods_log with previous=false returns current pod log", func(t *testing.T) {
743+
if err != nil {
744+
t.Fatalf("call tool failed %v", err)
745+
return
746+
}
747+
if podsPreviousLogFalse.IsError {
748+
t.Fatalf("call tool failed")
749+
return
750+
}
751+
})
722752
})
723753
}
724754

0 commit comments

Comments
 (0)