mirror of
https://github.com/amir20/dozzle.git
synced 2026-06-23 04:10:12 +00:00
refactor: replace JSON strings with typed proto messages in cloud tools (#4583)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+15
-24
@@ -40,10 +40,10 @@ type Client struct {
|
||||
apiKeyFunc func() string
|
||||
target string
|
||||
plaintext bool
|
||||
toolSem *semaphore.Weighted
|
||||
cachedToolsJSON []string
|
||||
cachedToolsOnce sync.Once
|
||||
startCh chan struct{}
|
||||
toolSem *semaphore.Weighted
|
||||
cachedTools []*pb.ToolDefinition
|
||||
toolsOnce sync.Once
|
||||
startCh chan struct{}
|
||||
}
|
||||
|
||||
// NewClient creates a new cloud gRPC client.
|
||||
@@ -254,29 +254,20 @@ func (c *Client) handleRequest(ctx context.Context, req *pb.ToolRequest) *pb.Too
|
||||
log.Debug().Str("request_id", req.RequestId).Msg("cloud requested tool list")
|
||||
resp.Type = &pb.ToolResponse_ListTools{
|
||||
ListTools: &pb.ListToolsResponse{
|
||||
ToolsJson: c.toolsJSON(),
|
||||
Tools: c.tools(),
|
||||
},
|
||||
}
|
||||
|
||||
case *pb.ToolRequest_CallTool:
|
||||
log.Debug().Str("request_id", req.RequestId).Str("tool", t.CallTool.Name).Str("args", t.CallTool.ArgumentsJson).Msg("cloud tool call received")
|
||||
result, err := ExecuteTool(ctx, t.CallTool.Name, t.CallTool.ArgumentsJson, c.enableActions, c.hostService, c.labels)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Str("request_id", req.RequestId).Str("tool", t.CallTool.Name).Msg("cloud tool call failed")
|
||||
resp.Type = &pb.ToolResponse_CallTool{
|
||||
CallTool: &pb.CallToolResponse{
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
},
|
||||
}
|
||||
callResp := ExecuteTool(ctx, t.CallTool.Name, t.CallTool.ArgumentsJson, c.enableActions, c.hostService, c.labels)
|
||||
if !callResp.Success {
|
||||
log.Debug().Str("error", callResp.Error).Str("request_id", req.RequestId).Str("tool", t.CallTool.Name).Msg("cloud tool call failed")
|
||||
} else {
|
||||
log.Debug().Str("request_id", req.RequestId).Str("tool", t.CallTool.Name).Msg("cloud tool call completed")
|
||||
resp.Type = &pb.ToolResponse_CallTool{
|
||||
CallTool: &pb.CallToolResponse{
|
||||
Success: true,
|
||||
ResultJson: result,
|
||||
},
|
||||
}
|
||||
}
|
||||
resp.Type = &pb.ToolResponse_CallTool{
|
||||
CallTool: callResp,
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -292,11 +283,11 @@ func (c *Client) handleRequest(ctx context.Context, req *pb.ToolRequest) *pb.Too
|
||||
return resp
|
||||
}
|
||||
|
||||
func (c *Client) toolsJSON() []string {
|
||||
c.cachedToolsOnce.Do(func() {
|
||||
c.cachedToolsJSON = marshalTools(c.enableActions)
|
||||
func (c *Client) tools() []*pb.ToolDefinition {
|
||||
c.toolsOnce.Do(func() {
|
||||
c.cachedTools = AvailableTools(c.enableActions)
|
||||
})
|
||||
return c.cachedToolsJSON
|
||||
return c.cachedTools
|
||||
}
|
||||
|
||||
func isPermissionDenied(err error) bool {
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
pb "github.com/amir20/dozzle/proto/cloud"
|
||||
"github.com/amir20/dozzle/internal/container"
|
||||
container_support "github.com/amir20/dozzle/internal/support/container"
|
||||
pb "github.com/amir20/dozzle/proto/cloud"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
@@ -48,7 +48,7 @@ func TestHandleRequest_ListTools(t *testing.T) {
|
||||
assert.Equal(t, "req-1", resp.RequestId)
|
||||
listResp := resp.GetListTools()
|
||||
assert.NotNil(t, listResp)
|
||||
assert.Len(t, listResp.ToolsJson, 4) // find_containers + 3 actions
|
||||
assert.Len(t, listResp.Tools, 7) // list_hosts + list_running_containers + list_all_containers + get_running_container_stats + 3 actions
|
||||
}
|
||||
|
||||
func TestHandleRequest_ListTools_ActionsDisabled(t *testing.T) {
|
||||
@@ -66,7 +66,7 @@ func TestHandleRequest_ListTools_ActionsDisabled(t *testing.T) {
|
||||
resp := client.handleRequest(context.Background(), req)
|
||||
|
||||
listResp := resp.GetListTools()
|
||||
assert.Len(t, listResp.ToolsJson, 1) // only list_containers
|
||||
assert.Len(t, listResp.Tools, 4) // list_hosts + list_running_containers + list_all_containers + get_running_container_stats
|
||||
}
|
||||
|
||||
func TestHandleRequest_CallTool_ListContainers(t *testing.T) {
|
||||
@@ -83,7 +83,7 @@ func TestHandleRequest_CallTool_ListContainers(t *testing.T) {
|
||||
RequestId: "req-3",
|
||||
Type: &pb.ToolRequest_CallTool{
|
||||
CallTool: &pb.CallToolRequest{
|
||||
Name: "find_containers",
|
||||
Name: "list_running_containers",
|
||||
ArgumentsJson: "",
|
||||
},
|
||||
},
|
||||
@@ -93,7 +93,10 @@ func TestHandleRequest_CallTool_ListContainers(t *testing.T) {
|
||||
|
||||
callResp := resp.GetCallTool()
|
||||
assert.True(t, callResp.Success)
|
||||
assert.Contains(t, callResp.ResultJson, "nginx")
|
||||
result := callResp.GetListContainers()
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result.Containers, 1)
|
||||
assert.Equal(t, "nginx", result.Containers[0].Name)
|
||||
}
|
||||
|
||||
func TestHandleRequest_CallTool_UnknownTool(t *testing.T) {
|
||||
|
||||
+206
-177
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/amir20/dozzle/internal/container"
|
||||
container_support "github.com/amir20/dozzle/internal/support/container"
|
||||
pb "github.com/amir20/dozzle/proto/cloud"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -15,56 +16,7 @@ import (
|
||||
type ToolHostService interface {
|
||||
ListAllContainers(labels container.ContainerLabels) ([]container.Container, []error)
|
||||
FindContainer(host string, id string, labels container.ContainerLabels) (*container_support.ContainerService, error)
|
||||
}
|
||||
|
||||
// FunctionDefinition describes a tool that can be called by the cloud service.
|
||||
type FunctionDefinition struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Parameters ParameterDefinition `json:"parameters"`
|
||||
}
|
||||
|
||||
// ParameterDefinition describes the JSON Schema parameters for a tool.
|
||||
type ParameterDefinition struct {
|
||||
Type string `json:"type"`
|
||||
Properties map[string]PropertyDefinition `json:"properties"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
}
|
||||
|
||||
// PropertyDefinition describes a single property in a tool's parameters.
|
||||
type PropertyDefinition struct {
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type containerResult struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Image string `json:"image"`
|
||||
Command string `json:"command"`
|
||||
Created string `json:"created"`
|
||||
StartedAt string `json:"startedAt"`
|
||||
FinishedAt string `json:"finishedAt,omitempty"`
|
||||
State string `json:"state"`
|
||||
Health string `json:"health,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
CPUPercent *float64 `json:"cpuPercent,omitempty"`
|
||||
MaxCPU5Min *float64 `json:"maxCpu5Min,omitempty"`
|
||||
MemoryPercent *float64 `json:"memoryPercent,omitempty"`
|
||||
MaxMemory5Min *float64 `json:"maxMemory5Min,omitempty"`
|
||||
}
|
||||
|
||||
var actionMap = map[string]container.ContainerAction{
|
||||
"start_container": container.Start,
|
||||
"stop_container": container.Stop,
|
||||
"restart_container": container.Restart,
|
||||
}
|
||||
|
||||
type actionResult struct {
|
||||
Success bool `json:"success"`
|
||||
ContainerID string `json:"containerId"`
|
||||
Action string `json:"action"`
|
||||
Hosts() []container.Host
|
||||
}
|
||||
|
||||
type containerActionArgs struct {
|
||||
@@ -73,49 +25,49 @@ type containerActionArgs struct {
|
||||
}
|
||||
|
||||
// AvailableTools returns the list of tool definitions based on configuration.
|
||||
// list_containers is always available. Action tools require enableActions.
|
||||
func AvailableTools(enableActions bool) []FunctionDefinition {
|
||||
tools := []FunctionDefinition{
|
||||
func AvailableTools(enableActions bool) []*pb.ToolDefinition {
|
||||
noParams := `{"type":"object","properties":{}}`
|
||||
|
||||
tools := []*pb.ToolDefinition{
|
||||
{
|
||||
Name: "find_containers",
|
||||
Description: "List all Docker containers with their current state, name, image, and host",
|
||||
Parameters: ParameterDefinition{
|
||||
Type: "object",
|
||||
Properties: map[string]PropertyDefinition{},
|
||||
},
|
||||
Name: "list_hosts",
|
||||
Description: "List all Docker hosts connected to Dozzle with their name, CPU cores, total memory, Docker version, and availability status.",
|
||||
ParametersJson: noParams,
|
||||
},
|
||||
{
|
||||
Name: "list_running_containers",
|
||||
Description: "List currently running Docker containers with their name, image, state, health status, and host. Only returns containers that are actively running.",
|
||||
ParametersJson: noParams,
|
||||
},
|
||||
{
|
||||
Name: "list_all_containers",
|
||||
Description: "List all Docker containers including stopped, exited, and previously run containers. Includes finished time for non-running containers.",
|
||||
ParametersJson: noParams,
|
||||
},
|
||||
{
|
||||
Name: "get_running_container_stats",
|
||||
Description: "Get real-time CPU and memory usage statistics for all currently running Docker containers. Returns current percentages and peak values over the last 5 minutes.",
|
||||
ParametersJson: noParams,
|
||||
},
|
||||
}
|
||||
|
||||
if enableActions {
|
||||
actionParams := ParameterDefinition{
|
||||
Type: "object",
|
||||
Properties: map[string]PropertyDefinition{
|
||||
"container_id": {
|
||||
Type: "string",
|
||||
Description: "The container ID",
|
||||
},
|
||||
"host": {
|
||||
Type: "string",
|
||||
Description: "The host name where the container is running",
|
||||
},
|
||||
},
|
||||
Required: []string{"container_id", "host"},
|
||||
}
|
||||
actionParams := `{"type":"object","properties":{"container_id":{"type":"string","description":"The container ID"},"host":{"type":"string","description":"The host name where the container is running"}},"required":["container_id","host"]}`
|
||||
tools = append(tools,
|
||||
FunctionDefinition{
|
||||
Name: "start_container",
|
||||
Description: "Start a stopped Docker container",
|
||||
Parameters: actionParams,
|
||||
&pb.ToolDefinition{
|
||||
Name: "start_container",
|
||||
Description: "Start a stopped Docker container",
|
||||
ParametersJson: actionParams,
|
||||
},
|
||||
FunctionDefinition{
|
||||
Name: "stop_container",
|
||||
Description: "Stop a running Docker container",
|
||||
Parameters: actionParams,
|
||||
&pb.ToolDefinition{
|
||||
Name: "stop_container",
|
||||
Description: "Stop a running Docker container",
|
||||
ParametersJson: actionParams,
|
||||
},
|
||||
FunctionDefinition{
|
||||
Name: "restart_container",
|
||||
Description: "Restart a Docker container",
|
||||
Parameters: actionParams,
|
||||
&pb.ToolDefinition{
|
||||
Name: "restart_container",
|
||||
Description: "Restart a Docker container",
|
||||
ParametersJson: actionParams,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -123,87 +75,192 @@ func AvailableTools(enableActions bool) []FunctionDefinition {
|
||||
return tools
|
||||
}
|
||||
|
||||
// marshalTools serializes tool definitions to JSON strings for the gRPC response.
|
||||
func marshalTools(enableActions bool) []string {
|
||||
tools := AvailableTools(enableActions)
|
||||
result := make([]string, 0, len(tools))
|
||||
for _, tool := range tools {
|
||||
data, err := json.Marshal(tool)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("tool", tool.Name).Msg("failed to marshal tool definition")
|
||||
continue
|
||||
}
|
||||
result = append(result, string(data))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ExecuteTool dispatches a tool call by name and returns JSON result.
|
||||
// ExecuteTool dispatches a tool call by name and returns a proto CallToolResponse.
|
||||
// enableActions must be true for action tools (start/stop/restart) to execute.
|
||||
func ExecuteTool(ctx context.Context, name string, argsJSON string, enableActions bool, hostService ToolHostService, labels container.ContainerLabels) (string, error) {
|
||||
switch name {
|
||||
case "find_containers":
|
||||
if ctx.Err() != nil {
|
||||
return "", ctx.Err()
|
||||
func ExecuteTool(ctx context.Context, name string, argsJSON string, enableActions bool, hostService ToolHostService, labels container.ContainerLabels) *pb.CallToolResponse {
|
||||
resp, err := executeTool(ctx, name, argsJSON, enableActions, hostService, labels)
|
||||
if err != nil {
|
||||
return &pb.CallToolResponse{
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
}
|
||||
return executeListContainers(hostService, labels)
|
||||
case "start_container", "stop_container", "restart_container":
|
||||
if !enableActions {
|
||||
return "", fmt.Errorf("container actions are not enabled")
|
||||
}
|
||||
return executeContainerAction(ctx, argsJSON, actionMap[name], hostService, labels)
|
||||
default:
|
||||
return "", fmt.Errorf("unknown tool: %s", name)
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func executeListContainers(hostService ToolHostService, labels container.ContainerLabels) (string, error) {
|
||||
containers, errs := hostService.ListAllContainers(labels)
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("error listing containers from host")
|
||||
}
|
||||
func executeTool(ctx context.Context, name string, argsJSON string, enableActions bool, hostService ToolHostService, labels container.ContainerLabels) (*pb.CallToolResponse, error) {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
results := make([]containerResult, len(containers))
|
||||
for i, c := range containers {
|
||||
r := containerResult{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
Image: c.Image,
|
||||
Command: c.Command,
|
||||
Created: c.Created.UTC().Format(time.RFC3339),
|
||||
StartedAt: c.StartedAt.UTC().Format(time.RFC3339),
|
||||
FinishedAt: formatTimeOrEmpty(c.FinishedAt),
|
||||
State: c.State,
|
||||
Health: c.Health,
|
||||
Host: c.Host,
|
||||
Group: c.Group,
|
||||
switch name {
|
||||
case "list_hosts":
|
||||
hosts := hostService.Hosts()
|
||||
result := make([]*pb.HostInfo, len(hosts))
|
||||
for i, h := range hosts {
|
||||
result[i] = &pb.HostInfo{
|
||||
Id: h.ID,
|
||||
Name: h.Name,
|
||||
NCpu: int32(h.NCPU),
|
||||
MemTotal: h.MemTotal,
|
||||
DockerVersion: h.DockerVersion,
|
||||
AgentVersion: h.AgentVersion,
|
||||
Type: h.Type,
|
||||
Available: h.Available,
|
||||
}
|
||||
}
|
||||
return &pb.CallToolResponse{
|
||||
Success: true,
|
||||
Result: &pb.CallToolResponse_ListHosts{ListHosts: &pb.ListHostsResult{Hosts: result}},
|
||||
}, nil
|
||||
|
||||
case "list_running_containers":
|
||||
containers, errs := hostService.ListAllContainers(labels)
|
||||
logHostErrors(errs)
|
||||
|
||||
result := make([]*pb.ContainerInfo, 0, len(containers))
|
||||
for _, c := range containers {
|
||||
if c.State != "running" {
|
||||
continue
|
||||
}
|
||||
result = append(result, containerToProto(c))
|
||||
}
|
||||
return &pb.CallToolResponse{
|
||||
Success: true,
|
||||
Result: &pb.CallToolResponse_ListContainers{ListContainers: &pb.ListContainersResult{Containers: result}},
|
||||
}, nil
|
||||
|
||||
case "list_all_containers":
|
||||
containers, errs := hostService.ListAllContainers(labels)
|
||||
logHostErrors(errs)
|
||||
|
||||
result := make([]*pb.ContainerInfo, 0, len(containers))
|
||||
for _, c := range containers {
|
||||
result = append(result, containerToProto(c))
|
||||
}
|
||||
return &pb.CallToolResponse{
|
||||
Success: true,
|
||||
Result: &pb.CallToolResponse_ListContainers{ListContainers: &pb.ListContainersResult{Containers: result}},
|
||||
}, nil
|
||||
|
||||
case "get_running_container_stats":
|
||||
containers, errs := hostService.ListAllContainers(labels)
|
||||
logHostErrors(errs)
|
||||
|
||||
result := make([]*pb.ContainerStatEntry, 0, len(containers))
|
||||
for _, c := range containers {
|
||||
if c.State != "running" {
|
||||
continue
|
||||
}
|
||||
if c.Stats == nil || c.Stats.Len() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if c.Stats != nil && c.Stats.Len() > 0 {
|
||||
stats := c.Stats.Data()
|
||||
latest := stats[len(stats)-1]
|
||||
r.CPUPercent = &latest.CPUPercent
|
||||
r.MemoryPercent = &latest.MemoryPercent
|
||||
|
||||
var maxCPU, maxMem float64
|
||||
for _, s := range stats {
|
||||
maxCPU = max(maxCPU, s.CPUPercent)
|
||||
maxMem = max(maxMem, s.MemoryPercent)
|
||||
}
|
||||
r.MaxCPU5Min = &maxCPU
|
||||
r.MaxMemory5Min = &maxMem
|
||||
|
||||
result = append(result, &pb.ContainerStatEntry{
|
||||
Id: c.ID,
|
||||
Name: c.Name,
|
||||
Host: c.Host,
|
||||
CpuPercent: latest.CPUPercent,
|
||||
MemoryPercent: latest.MemoryPercent,
|
||||
MemoryUsage: latest.MemoryUsage,
|
||||
MaxCpu_5Min: maxCPU,
|
||||
MaxMemory_5Min: maxMem,
|
||||
})
|
||||
}
|
||||
return &pb.CallToolResponse{
|
||||
Success: true,
|
||||
Result: &pb.CallToolResponse_ContainerStats{ContainerStats: &pb.ContainerStatsResult{Stats: result}},
|
||||
}, nil
|
||||
|
||||
case "start_container", "stop_container", "restart_container":
|
||||
if !enableActions {
|
||||
return nil, fmt.Errorf("container actions are not enabled")
|
||||
}
|
||||
var args containerActionArgs
|
||||
if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse arguments: %w", err)
|
||||
}
|
||||
|
||||
results[i] = r
|
||||
action, err := resolveAction(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actionResult, err := executeAction(ctx, args.Host, args.ContainerID, action, hostService, labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.CallToolResponse{
|
||||
Success: true,
|
||||
Result: &pb.CallToolResponse_Action{Action: actionResult},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown tool: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveAction(name string) (container.ContainerAction, error) {
|
||||
switch name {
|
||||
case "start_container":
|
||||
return container.Start, nil
|
||||
case "stop_container":
|
||||
return container.Stop, nil
|
||||
case "restart_container":
|
||||
return container.Restart, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown action: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func executeAction(ctx context.Context, host, containerID string, action container.ContainerAction, hostService ToolHostService, labels container.ContainerLabels) (*pb.ActionResult, error) {
|
||||
if containerID == "" {
|
||||
return nil, fmt.Errorf("container_id is required")
|
||||
}
|
||||
|
||||
data, err := json.Marshal(results)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal containers: %w", err)
|
||||
if host == "" {
|
||||
return nil, fmt.Errorf("host is required")
|
||||
}
|
||||
|
||||
cs, err := hostService.FindContainer(host, containerID, labels)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("container not found: %w", err)
|
||||
}
|
||||
|
||||
if err := cs.Action(ctx, action); err != nil {
|
||||
return nil, fmt.Errorf("action failed: %w", err)
|
||||
}
|
||||
|
||||
return &pb.ActionResult{
|
||||
Success: true,
|
||||
ContainerId: containerID,
|
||||
Action: string(action),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func containerToProto(c container.Container) *pb.ContainerInfo {
|
||||
return &pb.ContainerInfo{
|
||||
Id: c.ID,
|
||||
Name: c.Name,
|
||||
Image: c.Image,
|
||||
Command: c.Command,
|
||||
Created: c.Created.UTC().Format(time.RFC3339),
|
||||
StartedAt: c.StartedAt.UTC().Format(time.RFC3339),
|
||||
FinishedAt: formatTimeOrEmpty(c.FinishedAt),
|
||||
State: c.State,
|
||||
Health: c.Health,
|
||||
Host: c.Host,
|
||||
Group: c.Group,
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func formatTimeOrEmpty(t time.Time) string {
|
||||
@@ -213,38 +270,10 @@ func formatTimeOrEmpty(t time.Time) string {
|
||||
return t.UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func executeContainerAction(ctx context.Context, argsJSON string, action container.ContainerAction, hostService ToolHostService, labels container.ContainerLabels) (string, error) {
|
||||
var args containerActionArgs
|
||||
if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
|
||||
return "", fmt.Errorf("failed to parse arguments: %w", err)
|
||||
func logHostErrors(errs []error) {
|
||||
for _, err := range errs {
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("error listing containers from host")
|
||||
}
|
||||
}
|
||||
|
||||
if args.ContainerID == "" {
|
||||
return "", fmt.Errorf("container_id is required")
|
||||
}
|
||||
|
||||
if args.Host == "" {
|
||||
return "", fmt.Errorf("host is required")
|
||||
}
|
||||
|
||||
cs, err := hostService.FindContainer(args.Host, args.ContainerID, labels)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("container not found: %w", err)
|
||||
}
|
||||
|
||||
if err := cs.Action(ctx, action); err != nil {
|
||||
return "", fmt.Errorf("action failed: %w", err)
|
||||
}
|
||||
|
||||
result := actionResult{
|
||||
Success: true,
|
||||
ContainerID: args.ContainerID,
|
||||
Action: string(action),
|
||||
}
|
||||
|
||||
data, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal result: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
@@ -22,11 +21,14 @@ func TestAvailableTools_WithActionsEnabled(t *testing.T) {
|
||||
names[i] = tool.Name
|
||||
}
|
||||
|
||||
assert.Contains(t, names, "find_containers")
|
||||
assert.Contains(t, names, "list_hosts")
|
||||
assert.Contains(t, names, "list_running_containers")
|
||||
assert.Contains(t, names, "list_all_containers")
|
||||
assert.Contains(t, names, "get_running_container_stats")
|
||||
assert.Contains(t, names, "start_container")
|
||||
assert.Contains(t, names, "stop_container")
|
||||
assert.Contains(t, names, "restart_container")
|
||||
assert.Len(t, tools, 4)
|
||||
assert.Len(t, tools, 7)
|
||||
}
|
||||
|
||||
func TestAvailableTools_WithActionsDisabled(t *testing.T) {
|
||||
@@ -37,8 +39,11 @@ func TestAvailableTools_WithActionsDisabled(t *testing.T) {
|
||||
names[i] = tool.Name
|
||||
}
|
||||
|
||||
assert.Contains(t, names, "find_containers")
|
||||
assert.Len(t, tools, 1)
|
||||
assert.Contains(t, names, "list_hosts")
|
||||
assert.Contains(t, names, "list_running_containers")
|
||||
assert.Contains(t, names, "list_all_containers")
|
||||
assert.Contains(t, names, "get_running_container_stats")
|
||||
assert.Len(t, tools, 4)
|
||||
}
|
||||
|
||||
func TestAvailableTools_ParametersAreValid(t *testing.T) {
|
||||
@@ -47,7 +52,7 @@ func TestAvailableTools_ParametersAreValid(t *testing.T) {
|
||||
for _, tool := range tools {
|
||||
assert.NotEmpty(t, tool.Name)
|
||||
assert.NotEmpty(t, tool.Description)
|
||||
assert.NotNil(t, tool.Parameters)
|
||||
assert.NotEmpty(t, tool.ParametersJson)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +79,11 @@ func (m *MockHostService) FindContainer(host string, id string, labels container
|
||||
return args.Get(0).(*container_support.ContainerService), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockHostService) Hosts() []container.Host {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]container.Host)
|
||||
}
|
||||
|
||||
type MockClientService struct {
|
||||
mock.Mock
|
||||
}
|
||||
@@ -112,22 +122,39 @@ func (m *MockClientService) Exec(_ context.Context, _ container.Container, _ []s
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestExecuteTool_ListContainers(t *testing.T) {
|
||||
func TestExecuteTool_ListRunningContainers(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
mockHost.On("ListAllContainers", container.ContainerLabels(nil)).Return([]container.Container{
|
||||
{ID: "abc123", Name: "nginx", Image: "nginx:latest", State: "running", Host: "local"},
|
||||
{ID: "def456", Name: "redis", Image: "redis:7", State: "running", Host: "local"},
|
||||
{ID: "ghi789", Name: "stopped", Image: "alpine:latest", State: "exited", Host: "local"},
|
||||
}, nil)
|
||||
|
||||
result, err := ExecuteTool(context.Background(), "find_containers", "", false, mockHost, nil)
|
||||
assert.NoError(t, err)
|
||||
resp := ExecuteTool(context.Background(), "list_running_containers", "", false, mockHost, nil)
|
||||
assert.True(t, resp.Success)
|
||||
|
||||
var containers []map[string]any
|
||||
err = json.Unmarshal([]byte(result), &containers)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, containers, 2)
|
||||
assert.Equal(t, "abc123", containers[0]["id"])
|
||||
assert.Equal(t, "nginx", containers[0]["name"])
|
||||
result := resp.GetListContainers()
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result.Containers, 2)
|
||||
assert.Equal(t, "abc123", result.Containers[0].Id)
|
||||
assert.Equal(t, "nginx", result.Containers[0].Name)
|
||||
}
|
||||
|
||||
func TestExecuteTool_ListAllContainers(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
mockHost.On("ListAllContainers", container.ContainerLabels(nil)).Return([]container.Container{
|
||||
{ID: "abc123", Name: "nginx", Image: "nginx:latest", State: "running", Host: "local"},
|
||||
{ID: "def456", Name: "redis", Image: "redis:7", State: "exited", Host: "local"},
|
||||
}, nil)
|
||||
|
||||
resp := ExecuteTool(context.Background(), "list_all_containers", "", false, mockHost, nil)
|
||||
assert.True(t, resp.Success)
|
||||
|
||||
result := resp.GetListContainers()
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result.Containers, 2)
|
||||
assert.Equal(t, "abc123", result.Containers[0].Id)
|
||||
assert.Equal(t, "def456", result.Containers[1].Id)
|
||||
}
|
||||
|
||||
func TestExecuteTool_RestartContainer(t *testing.T) {
|
||||
@@ -140,9 +167,13 @@ func TestExecuteTool_RestartContainer(t *testing.T) {
|
||||
mockHost.On("FindContainer", "local", "abc123", container.ContainerLabels(nil)).Return(cs, nil)
|
||||
|
||||
argsJSON := `{"container_id": "abc123", "host": "local"}`
|
||||
result, err := ExecuteTool(context.Background(), "restart_container", argsJSON, true, mockHost, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, result, "success")
|
||||
resp := ExecuteTool(context.Background(), "restart_container", argsJSON, true, mockHost, nil)
|
||||
assert.True(t, resp.Success)
|
||||
|
||||
action := resp.GetAction()
|
||||
assert.NotNil(t, action)
|
||||
assert.True(t, action.Success)
|
||||
assert.Equal(t, "abc123", action.ContainerId)
|
||||
|
||||
mockClient.AssertCalled(t, "ContainerAction", mock.Anything, mock.Anything, container.Restart)
|
||||
}
|
||||
@@ -151,12 +182,12 @@ func TestExecuteTool_RestartContainer_ActionsDisabled(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
|
||||
argsJSON := `{"container_id": "abc123"}`
|
||||
_, err := ExecuteTool(context.Background(), "restart_container", argsJSON, false, mockHost, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "container actions are not enabled")
|
||||
resp := ExecuteTool(context.Background(), "restart_container", argsJSON, false, mockHost, nil)
|
||||
assert.False(t, resp.Success)
|
||||
assert.Contains(t, resp.Error, "container actions are not enabled")
|
||||
}
|
||||
|
||||
func TestExecuteTool_ListContainers_PartialHostError(t *testing.T) {
|
||||
func TestExecuteTool_ListRunningContainers_PartialHostError(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
mockHost.On("ListAllContainers", container.ContainerLabels(nil)).Return(
|
||||
[]container.Container{
|
||||
@@ -165,19 +196,37 @@ func TestExecuteTool_ListContainers_PartialHostError(t *testing.T) {
|
||||
[]error{fmt.Errorf("host2 unreachable")},
|
||||
)
|
||||
|
||||
result, err := ExecuteTool(context.Background(), "find_containers", "", false, mockHost, nil)
|
||||
assert.NoError(t, err)
|
||||
resp := ExecuteTool(context.Background(), "list_running_containers", "", false, mockHost, nil)
|
||||
assert.True(t, resp.Success)
|
||||
|
||||
var containers []map[string]any
|
||||
err = json.Unmarshal([]byte(result), &containers)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, containers, 1)
|
||||
result := resp.GetListContainers()
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result.Containers, 1)
|
||||
}
|
||||
|
||||
func TestExecuteTool_ListHosts(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
mockHost.On("Hosts").Return([]container.Host{
|
||||
{ID: "host1", Name: "server-1", NCPU: 4, MemTotal: 8589934592, DockerVersion: "24.0.7", Available: true},
|
||||
{ID: "host2", Name: "server-2", NCPU: 8, MemTotal: 17179869184, DockerVersion: "25.0.1", Available: false},
|
||||
})
|
||||
|
||||
resp := ExecuteTool(context.Background(), "list_hosts", "", false, mockHost, nil)
|
||||
assert.True(t, resp.Success)
|
||||
|
||||
result := resp.GetListHosts()
|
||||
assert.NotNil(t, result)
|
||||
assert.Len(t, result.Hosts, 2)
|
||||
assert.Equal(t, "host1", result.Hosts[0].Id)
|
||||
assert.Equal(t, "server-1", result.Hosts[0].Name)
|
||||
assert.Equal(t, true, result.Hosts[0].Available)
|
||||
assert.Equal(t, false, result.Hosts[1].Available)
|
||||
}
|
||||
|
||||
func TestExecuteTool_UnknownTool(t *testing.T) {
|
||||
mockHost := &MockHostService{}
|
||||
|
||||
_, err := ExecuteTool(context.Background(), "unknown_tool", "", false, mockHost, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "unknown tool")
|
||||
resp := ExecuteTool(context.Background(), "unknown_tool", "", false, mockHost, nil)
|
||||
assert.False(t, resp.Success)
|
||||
assert.Contains(t, resp.Error, "unknown tool")
|
||||
}
|
||||
|
||||
+771
-45
@@ -239,7 +239,7 @@ func (*ListToolsRequest) Descriptor() ([]byte, []int) {
|
||||
|
||||
type ListToolsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ToolsJson []string `protobuf:"bytes,1,rep,name=tools_json,json=toolsJson,proto3" json:"tools_json,omitempty"`
|
||||
Tools []*ToolDefinition `protobuf:"bytes,1,rep,name=tools,proto3" json:"tools,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -274,13 +274,73 @@ func (*ListToolsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ListToolsResponse) GetToolsJson() []string {
|
||||
func (x *ListToolsResponse) GetTools() []*ToolDefinition {
|
||||
if x != nil {
|
||||
return x.ToolsJson
|
||||
return x.Tools
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ToolDefinition struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
|
||||
ParametersJson string `protobuf:"bytes,3,opt,name=parameters_json,json=parametersJson,proto3" json:"parameters_json,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ToolDefinition) Reset() {
|
||||
*x = ToolDefinition{}
|
||||
mi := &file_cloud_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ToolDefinition) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ToolDefinition) ProtoMessage() {}
|
||||
|
||||
func (x *ToolDefinition) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ToolDefinition.ProtoReflect.Descriptor instead.
|
||||
func (*ToolDefinition) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ToolDefinition) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ToolDefinition) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ToolDefinition) GetParametersJson() string {
|
||||
if x != nil {
|
||||
return x.ParametersJson
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CallToolRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
@@ -291,7 +351,7 @@ type CallToolRequest struct {
|
||||
|
||||
func (x *CallToolRequest) Reset() {
|
||||
*x = CallToolRequest{}
|
||||
mi := &file_cloud_proto_msgTypes[4]
|
||||
mi := &file_cloud_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -303,7 +363,7 @@ func (x *CallToolRequest) String() string {
|
||||
func (*CallToolRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CallToolRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[4]
|
||||
mi := &file_cloud_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -316,7 +376,7 @@ func (x *CallToolRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CallToolRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CallToolRequest) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{4}
|
||||
return file_cloud_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *CallToolRequest) GetName() string {
|
||||
@@ -334,17 +394,23 @@ func (x *CallToolRequest) GetArgumentsJson() string {
|
||||
}
|
||||
|
||||
type CallToolResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
ResultJson string `protobuf:"bytes,2,opt,name=result_json,json=resultJson,proto3" json:"result_json,omitempty"`
|
||||
Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
|
||||
// Types that are valid to be assigned to Result:
|
||||
//
|
||||
// *CallToolResponse_ListHosts
|
||||
// *CallToolResponse_ListContainers
|
||||
// *CallToolResponse_ContainerStats
|
||||
// *CallToolResponse_Action
|
||||
Result isCallToolResponse_Result `protobuf_oneof:"result"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) Reset() {
|
||||
*x = CallToolResponse{}
|
||||
mi := &file_cloud_proto_msgTypes[5]
|
||||
mi := &file_cloud_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -356,7 +422,7 @@ func (x *CallToolResponse) String() string {
|
||||
func (*CallToolResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CallToolResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[5]
|
||||
mi := &file_cloud_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -369,7 +435,7 @@ func (x *CallToolResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CallToolResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CallToolResponse) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{5}
|
||||
return file_cloud_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetSuccess() bool {
|
||||
@@ -379,16 +445,600 @@ func (x *CallToolResponse) GetSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetResultJson() string {
|
||||
func (x *CallToolResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.ResultJson
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetError() string {
|
||||
func (x *CallToolResponse) GetResult() isCallToolResponse_Result {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
return x.Result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetListHosts() *ListHostsResult {
|
||||
if x != nil {
|
||||
if x, ok := x.Result.(*CallToolResponse_ListHosts); ok {
|
||||
return x.ListHosts
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetListContainers() *ListContainersResult {
|
||||
if x != nil {
|
||||
if x, ok := x.Result.(*CallToolResponse_ListContainers); ok {
|
||||
return x.ListContainers
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetContainerStats() *ContainerStatsResult {
|
||||
if x != nil {
|
||||
if x, ok := x.Result.(*CallToolResponse_ContainerStats); ok {
|
||||
return x.ContainerStats
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CallToolResponse) GetAction() *ActionResult {
|
||||
if x != nil {
|
||||
if x, ok := x.Result.(*CallToolResponse_Action); ok {
|
||||
return x.Action
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isCallToolResponse_Result interface {
|
||||
isCallToolResponse_Result()
|
||||
}
|
||||
|
||||
type CallToolResponse_ListHosts struct {
|
||||
ListHosts *ListHostsResult `protobuf:"bytes,3,opt,name=list_hosts,json=listHosts,proto3,oneof"`
|
||||
}
|
||||
|
||||
type CallToolResponse_ListContainers struct {
|
||||
ListContainers *ListContainersResult `protobuf:"bytes,4,opt,name=list_containers,json=listContainers,proto3,oneof"`
|
||||
}
|
||||
|
||||
type CallToolResponse_ContainerStats struct {
|
||||
ContainerStats *ContainerStatsResult `protobuf:"bytes,5,opt,name=container_stats,json=containerStats,proto3,oneof"`
|
||||
}
|
||||
|
||||
type CallToolResponse_Action struct {
|
||||
Action *ActionResult `protobuf:"bytes,6,opt,name=action,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*CallToolResponse_ListHosts) isCallToolResponse_Result() {}
|
||||
|
||||
func (*CallToolResponse_ListContainers) isCallToolResponse_Result() {}
|
||||
|
||||
func (*CallToolResponse_ContainerStats) isCallToolResponse_Result() {}
|
||||
|
||||
func (*CallToolResponse_Action) isCallToolResponse_Result() {}
|
||||
|
||||
// Host information
|
||||
type HostInfo struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
NCpu int32 `protobuf:"varint,3,opt,name=n_cpu,json=nCpu,proto3" json:"n_cpu,omitempty"`
|
||||
MemTotal int64 `protobuf:"varint,4,opt,name=mem_total,json=memTotal,proto3" json:"mem_total,omitempty"`
|
||||
DockerVersion string `protobuf:"bytes,5,opt,name=docker_version,json=dockerVersion,proto3" json:"docker_version,omitempty"`
|
||||
AgentVersion string `protobuf:"bytes,6,opt,name=agent_version,json=agentVersion,proto3" json:"agent_version,omitempty"`
|
||||
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Available bool `protobuf:"varint,8,opt,name=available,proto3" json:"available,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *HostInfo) Reset() {
|
||||
*x = HostInfo{}
|
||||
mi := &file_cloud_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HostInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HostInfo) ProtoMessage() {}
|
||||
|
||||
func (x *HostInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HostInfo.ProtoReflect.Descriptor instead.
|
||||
func (*HostInfo) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetNCpu() int32 {
|
||||
if x != nil {
|
||||
return x.NCpu
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetMemTotal() int64 {
|
||||
if x != nil {
|
||||
return x.MemTotal
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetDockerVersion() string {
|
||||
if x != nil {
|
||||
return x.DockerVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetAgentVersion() string {
|
||||
if x != nil {
|
||||
return x.AgentVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HostInfo) GetAvailable() bool {
|
||||
if x != nil {
|
||||
return x.Available
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ListHostsResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Hosts []*HostInfo `protobuf:"bytes,1,rep,name=hosts,proto3" json:"hosts,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListHostsResult) Reset() {
|
||||
*x = ListHostsResult{}
|
||||
mi := &file_cloud_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListHostsResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListHostsResult) ProtoMessage() {}
|
||||
|
||||
func (x *ListHostsResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListHostsResult.ProtoReflect.Descriptor instead.
|
||||
func (*ListHostsResult) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ListHostsResult) GetHosts() []*HostInfo {
|
||||
if x != nil {
|
||||
return x.Hosts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container information
|
||||
type ContainerInfo struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"`
|
||||
Command string `protobuf:"bytes,4,opt,name=command,proto3" json:"command,omitempty"`
|
||||
Created string `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"`
|
||||
StartedAt string `protobuf:"bytes,6,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
|
||||
FinishedAt string `protobuf:"bytes,7,opt,name=finished_at,json=finishedAt,proto3" json:"finished_at,omitempty"`
|
||||
State string `protobuf:"bytes,8,opt,name=state,proto3" json:"state,omitempty"`
|
||||
Health string `protobuf:"bytes,9,opt,name=health,proto3" json:"health,omitempty"`
|
||||
Host string `protobuf:"bytes,10,opt,name=host,proto3" json:"host,omitempty"`
|
||||
Group string `protobuf:"bytes,11,opt,name=group,proto3" json:"group,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) Reset() {
|
||||
*x = ContainerInfo{}
|
||||
mi := &file_cloud_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ContainerInfo) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ContainerInfo.ProtoReflect.Descriptor instead.
|
||||
func (*ContainerInfo) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetImage() string {
|
||||
if x != nil {
|
||||
return x.Image
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetCommand() string {
|
||||
if x != nil {
|
||||
return x.Command
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetCreated() string {
|
||||
if x != nil {
|
||||
return x.Created
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetStartedAt() string {
|
||||
if x != nil {
|
||||
return x.StartedAt
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetFinishedAt() string {
|
||||
if x != nil {
|
||||
return x.FinishedAt
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetState() string {
|
||||
if x != nil {
|
||||
return x.State
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetHealth() string {
|
||||
if x != nil {
|
||||
return x.Health
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetHost() string {
|
||||
if x != nil {
|
||||
return x.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerInfo) GetGroup() string {
|
||||
if x != nil {
|
||||
return x.Group
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListContainersResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Containers []*ContainerInfo `protobuf:"bytes,1,rep,name=containers,proto3" json:"containers,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListContainersResult) Reset() {
|
||||
*x = ListContainersResult{}
|
||||
mi := &file_cloud_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListContainersResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListContainersResult) ProtoMessage() {}
|
||||
|
||||
func (x *ListContainersResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListContainersResult.ProtoReflect.Descriptor instead.
|
||||
func (*ListContainersResult) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *ListContainersResult) GetContainers() []*ContainerInfo {
|
||||
if x != nil {
|
||||
return x.Containers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container stats
|
||||
type ContainerStatEntry struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"`
|
||||
CpuPercent float64 `protobuf:"fixed64,4,opt,name=cpu_percent,json=cpuPercent,proto3" json:"cpu_percent,omitempty"`
|
||||
MemoryPercent float64 `protobuf:"fixed64,5,opt,name=memory_percent,json=memoryPercent,proto3" json:"memory_percent,omitempty"`
|
||||
MemoryUsage float64 `protobuf:"fixed64,6,opt,name=memory_usage,json=memoryUsage,proto3" json:"memory_usage,omitempty"`
|
||||
MaxCpu_5Min float64 `protobuf:"fixed64,7,opt,name=max_cpu_5min,json=maxCpu5min,proto3" json:"max_cpu_5min,omitempty"`
|
||||
MaxMemory_5Min float64 `protobuf:"fixed64,8,opt,name=max_memory_5min,json=maxMemory5min,proto3" json:"max_memory_5min,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) Reset() {
|
||||
*x = ContainerStatEntry{}
|
||||
mi := &file_cloud_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ContainerStatEntry) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerStatEntry) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ContainerStatEntry.ProtoReflect.Descriptor instead.
|
||||
func (*ContainerStatEntry) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetHost() string {
|
||||
if x != nil {
|
||||
return x.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetCpuPercent() float64 {
|
||||
if x != nil {
|
||||
return x.CpuPercent
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetMemoryPercent() float64 {
|
||||
if x != nil {
|
||||
return x.MemoryPercent
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetMemoryUsage() float64 {
|
||||
if x != nil {
|
||||
return x.MemoryUsage
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetMaxCpu_5Min() float64 {
|
||||
if x != nil {
|
||||
return x.MaxCpu_5Min
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ContainerStatEntry) GetMaxMemory_5Min() float64 {
|
||||
if x != nil {
|
||||
return x.MaxMemory_5Min
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ContainerStatsResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Stats []*ContainerStatEntry `protobuf:"bytes,1,rep,name=stats,proto3" json:"stats,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ContainerStatsResult) Reset() {
|
||||
*x = ContainerStatsResult{}
|
||||
mi := &file_cloud_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerStatsResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ContainerStatsResult) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerStatsResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ContainerStatsResult.ProtoReflect.Descriptor instead.
|
||||
func (*ContainerStatsResult) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *ContainerStatsResult) GetStats() []*ContainerStatEntry {
|
||||
if x != nil {
|
||||
return x.Stats
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Container action result
|
||||
type ActionResult struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"`
|
||||
Action string `protobuf:"bytes,3,opt,name=action,proto3" json:"action,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActionResult) Reset() {
|
||||
*x = ActionResult{}
|
||||
mi := &file_cloud_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ActionResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ActionResult) ProtoMessage() {}
|
||||
|
||||
func (x *ActionResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cloud_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActionResult.ProtoReflect.Descriptor instead.
|
||||
func (*ActionResult) Descriptor() ([]byte, []int) {
|
||||
return file_cloud_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *ActionResult) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ActionResult) GetContainerId() string {
|
||||
if x != nil {
|
||||
return x.ContainerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActionResult) GetAction() string {
|
||||
if x != nil {
|
||||
return x.Action
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -412,18 +1062,72 @@ const file_cloud_proto_rawDesc = "" +
|
||||
"list_tools\x18\x02 \x01(\v2\x18.cloud.ListToolsResponseH\x00R\tlistTools\x126\n" +
|
||||
"\tcall_tool\x18\x03 \x01(\v2\x17.cloud.CallToolResponseH\x00R\bcallToolB\x06\n" +
|
||||
"\x04type\"\x12\n" +
|
||||
"\x10ListToolsRequest\"2\n" +
|
||||
"\x11ListToolsResponse\x12\x1d\n" +
|
||||
"\n" +
|
||||
"tools_json\x18\x01 \x03(\tR\ttoolsJson\"L\n" +
|
||||
"\x10ListToolsRequest\"@\n" +
|
||||
"\x11ListToolsResponse\x12+\n" +
|
||||
"\x05tools\x18\x01 \x03(\v2\x15.cloud.ToolDefinitionR\x05tools\"o\n" +
|
||||
"\x0eToolDefinition\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12 \n" +
|
||||
"\vdescription\x18\x02 \x01(\tR\vdescription\x12'\n" +
|
||||
"\x0fparameters_json\x18\x03 \x01(\tR\x0eparametersJson\"L\n" +
|
||||
"\x0fCallToolRequest\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12%\n" +
|
||||
"\x0earguments_json\x18\x02 \x01(\tR\rargumentsJson\"c\n" +
|
||||
"\x0earguments_json\x18\x02 \x01(\tR\rargumentsJson\"\xc4\x02\n" +
|
||||
"\x10CallToolResponse\x12\x18\n" +
|
||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1f\n" +
|
||||
"\vresult_json\x18\x02 \x01(\tR\n" +
|
||||
"resultJson\x12\x14\n" +
|
||||
"\x05error\x18\x03 \x01(\tR\x05error2M\n" +
|
||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x14\n" +
|
||||
"\x05error\x18\x02 \x01(\tR\x05error\x127\n" +
|
||||
"\n" +
|
||||
"list_hosts\x18\x03 \x01(\v2\x16.cloud.ListHostsResultH\x00R\tlistHosts\x12F\n" +
|
||||
"\x0flist_containers\x18\x04 \x01(\v2\x1b.cloud.ListContainersResultH\x00R\x0elistContainers\x12F\n" +
|
||||
"\x0fcontainer_stats\x18\x05 \x01(\v2\x1b.cloud.ContainerStatsResultH\x00R\x0econtainerStats\x12-\n" +
|
||||
"\x06action\x18\x06 \x01(\v2\x13.cloud.ActionResultH\x00R\x06actionB\b\n" +
|
||||
"\x06result\"\xde\x01\n" +
|
||||
"\bHostInfo\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x13\n" +
|
||||
"\x05n_cpu\x18\x03 \x01(\x05R\x04nCpu\x12\x1b\n" +
|
||||
"\tmem_total\x18\x04 \x01(\x03R\bmemTotal\x12%\n" +
|
||||
"\x0edocker_version\x18\x05 \x01(\tR\rdockerVersion\x12#\n" +
|
||||
"\ragent_version\x18\x06 \x01(\tR\fagentVersion\x12\x12\n" +
|
||||
"\x04type\x18\a \x01(\tR\x04type\x12\x1c\n" +
|
||||
"\tavailable\x18\b \x01(\bR\tavailable\"8\n" +
|
||||
"\x0fListHostsResult\x12%\n" +
|
||||
"\x05hosts\x18\x01 \x03(\v2\x0f.cloud.HostInfoR\x05hosts\"\x95\x02\n" +
|
||||
"\rContainerInfo\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" +
|
||||
"\x05image\x18\x03 \x01(\tR\x05image\x12\x18\n" +
|
||||
"\acommand\x18\x04 \x01(\tR\acommand\x12\x18\n" +
|
||||
"\acreated\x18\x05 \x01(\tR\acreated\x12\x1d\n" +
|
||||
"\n" +
|
||||
"started_at\x18\x06 \x01(\tR\tstartedAt\x12\x1f\n" +
|
||||
"\vfinished_at\x18\a \x01(\tR\n" +
|
||||
"finishedAt\x12\x14\n" +
|
||||
"\x05state\x18\b \x01(\tR\x05state\x12\x16\n" +
|
||||
"\x06health\x18\t \x01(\tR\x06health\x12\x12\n" +
|
||||
"\x04host\x18\n" +
|
||||
" \x01(\tR\x04host\x12\x14\n" +
|
||||
"\x05group\x18\v \x01(\tR\x05group\"L\n" +
|
||||
"\x14ListContainersResult\x124\n" +
|
||||
"\n" +
|
||||
"containers\x18\x01 \x03(\v2\x14.cloud.ContainerInfoR\n" +
|
||||
"containers\"\x81\x02\n" +
|
||||
"\x12ContainerStatEntry\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04host\x18\x03 \x01(\tR\x04host\x12\x1f\n" +
|
||||
"\vcpu_percent\x18\x04 \x01(\x01R\n" +
|
||||
"cpuPercent\x12%\n" +
|
||||
"\x0ememory_percent\x18\x05 \x01(\x01R\rmemoryPercent\x12!\n" +
|
||||
"\fmemory_usage\x18\x06 \x01(\x01R\vmemoryUsage\x12 \n" +
|
||||
"\fmax_cpu_5min\x18\a \x01(\x01R\n" +
|
||||
"maxCpu5min\x12&\n" +
|
||||
"\x0fmax_memory_5min\x18\b \x01(\x01R\rmaxMemory5min\"G\n" +
|
||||
"\x14ContainerStatsResult\x12/\n" +
|
||||
"\x05stats\x18\x01 \x03(\v2\x19.cloud.ContainerStatEntryR\x05stats\"c\n" +
|
||||
"\fActionResult\x12\x18\n" +
|
||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12!\n" +
|
||||
"\fcontainer_id\x18\x02 \x01(\tR\vcontainerId\x12\x16\n" +
|
||||
"\x06action\x18\x03 \x01(\tR\x06action2M\n" +
|
||||
"\x10CloudToolService\x129\n" +
|
||||
"\n" +
|
||||
"ToolStream\x12\x13.cloud.ToolResponse\x1a\x12.cloud.ToolRequest(\x010\x01B&Z$github.com/amir20/dozzle/proto/cloudb\x06proto3"
|
||||
@@ -440,27 +1144,43 @@ func file_cloud_proto_rawDescGZIP() []byte {
|
||||
return file_cloud_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_cloud_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_cloud_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
|
||||
var file_cloud_proto_goTypes = []any{
|
||||
(*ToolRequest)(nil), // 0: cloud.ToolRequest
|
||||
(*ToolResponse)(nil), // 1: cloud.ToolResponse
|
||||
(*ListToolsRequest)(nil), // 2: cloud.ListToolsRequest
|
||||
(*ListToolsResponse)(nil), // 3: cloud.ListToolsResponse
|
||||
(*CallToolRequest)(nil), // 4: cloud.CallToolRequest
|
||||
(*CallToolResponse)(nil), // 5: cloud.CallToolResponse
|
||||
(*ToolRequest)(nil), // 0: cloud.ToolRequest
|
||||
(*ToolResponse)(nil), // 1: cloud.ToolResponse
|
||||
(*ListToolsRequest)(nil), // 2: cloud.ListToolsRequest
|
||||
(*ListToolsResponse)(nil), // 3: cloud.ListToolsResponse
|
||||
(*ToolDefinition)(nil), // 4: cloud.ToolDefinition
|
||||
(*CallToolRequest)(nil), // 5: cloud.CallToolRequest
|
||||
(*CallToolResponse)(nil), // 6: cloud.CallToolResponse
|
||||
(*HostInfo)(nil), // 7: cloud.HostInfo
|
||||
(*ListHostsResult)(nil), // 8: cloud.ListHostsResult
|
||||
(*ContainerInfo)(nil), // 9: cloud.ContainerInfo
|
||||
(*ListContainersResult)(nil), // 10: cloud.ListContainersResult
|
||||
(*ContainerStatEntry)(nil), // 11: cloud.ContainerStatEntry
|
||||
(*ContainerStatsResult)(nil), // 12: cloud.ContainerStatsResult
|
||||
(*ActionResult)(nil), // 13: cloud.ActionResult
|
||||
}
|
||||
var file_cloud_proto_depIdxs = []int32{
|
||||
2, // 0: cloud.ToolRequest.list_tools:type_name -> cloud.ListToolsRequest
|
||||
4, // 1: cloud.ToolRequest.call_tool:type_name -> cloud.CallToolRequest
|
||||
3, // 2: cloud.ToolResponse.list_tools:type_name -> cloud.ListToolsResponse
|
||||
5, // 3: cloud.ToolResponse.call_tool:type_name -> cloud.CallToolResponse
|
||||
1, // 4: cloud.CloudToolService.ToolStream:input_type -> cloud.ToolResponse
|
||||
0, // 5: cloud.CloudToolService.ToolStream:output_type -> cloud.ToolRequest
|
||||
5, // [5:6] is the sub-list for method output_type
|
||||
4, // [4:5] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
2, // 0: cloud.ToolRequest.list_tools:type_name -> cloud.ListToolsRequest
|
||||
5, // 1: cloud.ToolRequest.call_tool:type_name -> cloud.CallToolRequest
|
||||
3, // 2: cloud.ToolResponse.list_tools:type_name -> cloud.ListToolsResponse
|
||||
6, // 3: cloud.ToolResponse.call_tool:type_name -> cloud.CallToolResponse
|
||||
4, // 4: cloud.ListToolsResponse.tools:type_name -> cloud.ToolDefinition
|
||||
8, // 5: cloud.CallToolResponse.list_hosts:type_name -> cloud.ListHostsResult
|
||||
10, // 6: cloud.CallToolResponse.list_containers:type_name -> cloud.ListContainersResult
|
||||
12, // 7: cloud.CallToolResponse.container_stats:type_name -> cloud.ContainerStatsResult
|
||||
13, // 8: cloud.CallToolResponse.action:type_name -> cloud.ActionResult
|
||||
7, // 9: cloud.ListHostsResult.hosts:type_name -> cloud.HostInfo
|
||||
9, // 10: cloud.ListContainersResult.containers:type_name -> cloud.ContainerInfo
|
||||
11, // 11: cloud.ContainerStatsResult.stats:type_name -> cloud.ContainerStatEntry
|
||||
1, // 12: cloud.CloudToolService.ToolStream:input_type -> cloud.ToolResponse
|
||||
0, // 13: cloud.CloudToolService.ToolStream:output_type -> cloud.ToolRequest
|
||||
13, // [13:14] is the sub-list for method output_type
|
||||
12, // [12:13] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_cloud_proto_init() }
|
||||
@@ -476,13 +1196,19 @@ func file_cloud_proto_init() {
|
||||
(*ToolResponse_ListTools)(nil),
|
||||
(*ToolResponse_CallTool)(nil),
|
||||
}
|
||||
file_cloud_proto_msgTypes[6].OneofWrappers = []any{
|
||||
(*CallToolResponse_ListHosts)(nil),
|
||||
(*CallToolResponse_ListContainers)(nil),
|
||||
(*CallToolResponse_ContainerStats)(nil),
|
||||
(*CallToolResponse_Action)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_cloud_proto_rawDesc), len(file_cloud_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumMessages: 14,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
+72
-3
@@ -28,7 +28,13 @@ message ToolResponse {
|
||||
message ListToolsRequest {}
|
||||
|
||||
message ListToolsResponse {
|
||||
repeated string tools_json = 1;
|
||||
repeated ToolDefinition tools = 1;
|
||||
}
|
||||
|
||||
message ToolDefinition {
|
||||
string name = 1;
|
||||
string description = 2;
|
||||
string parameters_json = 3;
|
||||
}
|
||||
|
||||
message CallToolRequest {
|
||||
@@ -38,6 +44,69 @@ message CallToolRequest {
|
||||
|
||||
message CallToolResponse {
|
||||
bool success = 1;
|
||||
string result_json = 2;
|
||||
string error = 3;
|
||||
string error = 2;
|
||||
oneof result {
|
||||
ListHostsResult list_hosts = 3;
|
||||
ListContainersResult list_containers = 4;
|
||||
ContainerStatsResult container_stats = 5;
|
||||
ActionResult action = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Host information
|
||||
message HostInfo {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
int32 n_cpu = 3;
|
||||
int64 mem_total = 4;
|
||||
string docker_version = 5;
|
||||
string agent_version = 6;
|
||||
string type = 7;
|
||||
bool available = 8;
|
||||
}
|
||||
|
||||
message ListHostsResult {
|
||||
repeated HostInfo hosts = 1;
|
||||
}
|
||||
|
||||
// Container information
|
||||
message ContainerInfo {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string image = 3;
|
||||
string command = 4;
|
||||
string created = 5;
|
||||
string started_at = 6;
|
||||
string finished_at = 7;
|
||||
string state = 8;
|
||||
string health = 9;
|
||||
string host = 10;
|
||||
string group = 11;
|
||||
}
|
||||
|
||||
message ListContainersResult {
|
||||
repeated ContainerInfo containers = 1;
|
||||
}
|
||||
|
||||
// Container stats
|
||||
message ContainerStatEntry {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string host = 3;
|
||||
double cpu_percent = 4;
|
||||
double memory_percent = 5;
|
||||
double memory_usage = 6;
|
||||
double max_cpu_5min = 7;
|
||||
double max_memory_5min = 8;
|
||||
}
|
||||
|
||||
message ContainerStatsResult {
|
||||
repeated ContainerStatEntry stats = 1;
|
||||
}
|
||||
|
||||
// Container action result
|
||||
message ActionResult {
|
||||
bool success = 1;
|
||||
string container_id = 2;
|
||||
string action = 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user