Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions pkg/kubernetes/pods.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package kubernetes

import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"strings"

"github.com/containers/kubernetes-mcp-server/pkg/version"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand All @@ -18,9 +21,6 @@ import (
"k8s.io/client-go/tools/remotecommand"
"k8s.io/metrics/pkg/apis/metrics"
metricsv1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1"
"k8s.io/utils/ptr"

"github.com/containers/kubernetes-mcp-server/pkg/version"
)

// DefaultTailLines is the default number of lines to retrieve from the end of the logs
Expand Down Expand Up @@ -94,32 +94,36 @@ func (k *Kubernetes) PodsDelete(ctx context.Context, namespace, name string) (st
k.ResourcesDelete(ctx, &schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, namespace, name)
}

func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string, previous bool, tail int64) (string, error) {
func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string, previous bool, tail int64, query string) (string, error) {
pods := k.AccessControlClientset().CoreV1().Pods(k.NamespaceOrDefault(namespace))

logOptions := &v1.PodLogOptions{
Container: container,
Previous: previous,
}

// Only set tailLines if a value is provided (non-zero)
if tail > 0 {
logOptions.TailLines = &tail
} else {
// Default to DefaultTailLines lines when not specified
logOptions.TailLines = ptr.To(DefaultTailLines)
req := pods.GetLogs(name, logOptions)
stream, err := req.Stream(ctx)
if err != nil {
return "", errors.New("failed to open get Log stream")
}
defer stream.Close()

req := pods.GetLogs(name, logOptions)
res := req.Do(ctx)
if res.Error() != nil {
return "", res.Error()
logData := make([]string, 0)
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, query) {
logData = append(logData, line)
}
}
rawData, err := res.Raw()
if err != nil {
return "", err

rows := int64(len(logData))
if rows >= tail {
logData = logData[rows-tail : rows]
}
return string(rawData), nil
result := strings.Join(logData, "\n")
return result, nil
}

func (k *Kubernetes) PodsRun(ctx context.Context, namespace, name, image string, port int32) ([]*unstructured.Unstructured, error) {
Expand Down
14 changes: 12 additions & 2 deletions pkg/toolsets/core/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,12 @@ func initPods() []api.ServerTool {
Type: "boolean",
Description: "Return previous terminated container logs (Optional)",
},
"query": {
Type: "string",
Description: "filter logs by query",
},
},
Required: []string{"name"},
Required: []string{"name", "query"},
},
Annotations: api.ToolAnnotations{
Title: "Pods: Log",
Expand Down Expand Up @@ -404,7 +408,13 @@ func podsLog(params api.ToolHandlerParams) (*api.ToolCallResult, error) {
}
}

ret, err := params.PodsLog(params.Context, ns.(string), name.(string), container.(string), previousBool, tailInt)
query := params.GetArguments()["query"]
if query == nil {
query = ""
}

ret, err := params.PodsLog(params.Context, ns.(string), name.(string), container.(string), previousBool, tailInt,
query.(string))
if err != nil {
return api.NewToolCallResult("", fmt.Errorf("failed to get pod %s log in namespace %s: %v", name, ns, err)), nil
} else if ret == "" {
Expand Down