| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package tools
- import (
- "context"
- "encoding/json"
- "fmt"
- "strconv"
- "strings"
- "time"
- "github.com/mark3labs/mcp-go/mcp"
- "yunion.io/x/log"
- "yunion.io/x/onecloud/pkg/mcp-server/adapters"
- "yunion.io/x/onecloud/pkg/mcp-server/models"
- )
- // CloudpodsServerMonitorTool 用于获取Cloudpods虚拟机监控信息
- type CloudpodsServerMonitorTool struct {
- // adapter 用于与 Cloudpods API 进行交互
- adapter *adapters.CloudpodsAdapter
- }
- // NewCloudpodsServerMonitorTool 创建一个新的CloudpodsServerMonitorTool实例
- // adapter: 用于与Cloudpods API交互的适配器
- // 返回值: CloudpodsServerMonitorTool实例指针
- func NewCloudpodsServerMonitorTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerMonitorTool {
- return &CloudpodsServerMonitorTool{
- adapter: adapter,
- }
- }
- // GetTool 定义并返回获取虚拟机监控信息工具的元数据
- // 该工具用于获取Cloudpods虚拟机的监控信息,包括CPU、内存、磁盘、网络等指标
- // server_id: 虚拟机ID (必填)
- // start_time: 开始时间戳(秒),默认为1小时前
- // end_time: 结束时间戳(秒),默认为当前时间
- // metrics: 监控指标,多个用逗号分隔,例如:cpu_usage,mem_usage,disk_usage,net_bps_rx,net_bps_tx
- // ak: 用户登录cloudpods后获取的access key
- // sk: 用户登录cloudpods后获取的secret key
- func (c *CloudpodsServerMonitorTool) GetTool() mcp.Tool {
- return mcp.NewTool(
- "cloudpods_get_server_monitor",
- mcp.WithDescription("获取Cloudpods虚拟机监控信息,包括CPU、内存、磁盘、网络等指标"),
- mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID")),
- mcp.WithString("start_time", mcp.Description("开始时间戳(秒),默认为1小时前")),
- mcp.WithString("end_time", mcp.Description("结束时间戳(秒),默认为当前时间")),
- mcp.WithString("metrics", mcp.Description("监控指标,多个用逗号分隔,例如:cpu_usage,mem_usage,disk_usage,net_bps_rx,net_bps_tx")),
- mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
- mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
- )
- }
- // Handle 处理获取虚拟机监控信息的请求
- // ctx: 控制生命周期的上下文
- // req: 包含获取监控信息所需参数的请求对象
- // 返回值: 包含监控信息的响应对象和可能的错误
- func (c *CloudpodsServerMonitorTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
- // 获取必填参数:虚拟机ID
- serverID, err := req.RequireString("server_id")
- if err != nil {
- return nil, err
- }
- // 设置默认时间范围:结束时间为当前时间,开始时间为1小时前
- now := time.Now().Unix()
- startTime := now - 3600
- // 解析开始时间参数,如果指定则使用指定值
- if startTimeStr := req.GetString("start_time", ""); startTimeStr != "" {
- if parsedStartTime, err := strconv.ParseInt(startTimeStr, 10, 64); err == nil {
- startTime = parsedStartTime
- }
- }
- // 解析结束时间参数,如果指定则使用指定值
- endTime := now
- if endTimeStr := req.GetString("end_time", ""); endTimeStr != "" {
- if parsedEndTime, err := strconv.ParseInt(endTimeStr, 10, 64); err == nil {
- endTime = parsedEndTime
- }
- }
- // 获取可选参数:监控指标
- var metrics []string
- if metricsStr := req.GetString("metrics", ""); metricsStr != "" {
- metrics = strings.Split(metricsStr, ",")
- for i, metric := range metrics {
- metrics[i] = strings.TrimSpace(metric)
- }
- } else {
- metrics = []string{"cpu_usage", "mem_usage", "disk_usage", "net_bps_rx", "net_bps_tx"}
- }
- // 获取ak和sk参数,用于认证
- ak := req.GetString("ak", "")
- sk := req.GetString("sk", "")
- // 调用适配器获取虚拟机监控信息
- monitorResponse, err := c.adapter.GetServerMonitor(ctx, serverID, startTime, endTime, metrics, ak, sk)
- if err != nil {
- log.Errorf("Fail to get server monitor: %s", err)
- return nil, fmt.Errorf("fail to get server monitor: %w", err)
- }
- // 格式化监控结果
- formattedResult := c.formatMonitorResult(monitorResponse, serverID, startTime, endTime, metrics)
- // 将结果序列化为JSON格式
- resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
- if err != nil {
- log.Errorf("Fail to serialize result: %s", err)
- return nil, fmt.Errorf("fail to serialize result: %w", err)
- }
- // 返回格式化后的结果
- return mcp.NewToolResultText(string(resultJSON)), nil
- }
- // GetName 返回工具的名称标识符
- // 返回值: 工具名称字符串,用于唯一标识该工具
- func (c *CloudpodsServerMonitorTool) GetName() string {
- return "cloudpods_get_server_monitor"
- }
- // formatMonitorResult 格式化虚拟机监控信息的响应结果
- // response: 原始监控响应数据
- // serverID: 虚拟机ID
- // startTime: 监控开始时间
- // endTime: 监控结束时间
- // requestedMetrics: 请求的监控指标
- // 返回值: 包含监控信息的格式化结果
- func (c *CloudpodsServerMonitorTool) formatMonitorResult(response *models.MonitorResponse, serverID string, startTime, endTime int64, requestedMetrics []string) map[string]interface{} {
- // 初始化格式化结果结构
- formatted := map[string]interface{}{
- // 添加请求的基本信息
- "query_info": map[string]interface{}{
- "server_id": serverID,
- "start_time": startTime,
- "end_time": endTime,
- "start_time_human": time.Unix(startTime, 0).Format("2006-01-02 15:04:05"),
- "end_time_human": time.Unix(endTime, 0).Format("2006-01-02 15:04:05"),
- "requested_metrics": requestedMetrics,
- "duration_seconds": endTime - startTime,
- },
- "status": response.Status,
- "metrics": make([]map[string]interface{}, 0, len(response.Data.Metrics)),
- }
- for _, metric := range response.Data.Metrics {
- metricInfo := map[string]interface{}{
- "metric": metric.Metric,
- "unit": metric.Unit,
- "data_points": len(metric.Values),
- "values": make([]map[string]interface{}, 0, len(metric.Values)),
- }
- var totalValue float64
- var minValue, maxValue float64
- var latestValue float64
- var latestTime int64
- for i, value := range metric.Values {
- valueInfo := map[string]interface{}{
- "timestamp": value.Timestamp,
- "time_human": time.Unix(value.Timestamp, 0).Format("2006-01-02 15:04:05"),
- "value": value.Value,
- }
- metricInfo["values"] = append(metricInfo["values"].([]map[string]interface{}), valueInfo)
- totalValue += value.Value
- if i == 0 {
- minValue = value.Value
- maxValue = value.Value
- } else {
- if value.Value < minValue {
- minValue = value.Value
- }
- if value.Value > maxValue {
- maxValue = value.Value
- }
- }
- if value.Timestamp > latestTime {
- latestTime = value.Timestamp
- latestValue = value.Value
- }
- }
- if len(metric.Values) > 0 {
- metricInfo["statistics"] = map[string]interface{}{
- "min": minValue,
- "max": maxValue,
- "average": totalValue / float64(len(metric.Values)),
- "latest": latestValue,
- }
- }
- formatted["metrics"] = append(formatted["metrics"].([]map[string]interface{}), metricInfo)
- }
- formatted["summary"] = map[string]interface{}{
- "total_metrics": len(response.Data.Metrics),
- "query_successful": response.Status == 200,
- "time_range_hours": float64(endTime-startTime) / 3600,
- }
- return formatted
- }
- // CloudpodsServerStatsTool 用于获取Cloudpods虚拟机实时统计信息
- type CloudpodsServerStatsTool struct {
- // adapter 用于与 Cloudpods API 进行交互
- adapter *adapters.CloudpodsAdapter
- }
- // NewCloudpodsServerStatsTool 创建一个新的CloudpodsServerStatsTool实例
- // adapter: 用于与Cloudpods API交互的适配器
- // 返回值: CloudpodsServerStatsTool实例指针
- func NewCloudpodsServerStatsTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerStatsTool {
- return &CloudpodsServerStatsTool{
- adapter: adapter,
- }
- }
- // GetTool 定义并返回获取虚拟机统计信息工具的元数据
- // 该工具用于获取Cloudpods虚拟机的实时统计信息,包括CPU使用率、内存使用率、磁盘使用率和网络流量
- // server_id: 虚拟机ID (必填)
- // ak: 用户登录cloudpods后获取的access key
- // sk: 用户登录cloudpods后获取的secret key
- func (c *CloudpodsServerStatsTool) GetTool() mcp.Tool {
- return mcp.NewTool(
- "cloudpods_get_server_stats",
- mcp.WithDescription("获取Cloudpods虚拟机实时统计信息,包括CPU使用率、内存使用率、磁盘使用率和网络流量"),
- mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID")),
- mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
- mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
- )
- }
- // Handle 处理获取虚拟机统计信息的请求
- // ctx: 控制生命周期的上下文
- // req: 包含获取统计信息所需参数的请求对象
- // 返回值: 包含统计信息的响应对象和可能的错误
- func (c *CloudpodsServerStatsTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
- // 获取必填参数:虚拟机ID
- serverID, err := req.RequireString("server_id")
- if err != nil {
- return nil, err
- }
- // 获取可选参数:访问凭证
- ak := req.GetString("ak", "")
- sk := req.GetString("sk", "")
- // 调用适配器获取虚拟机统计信息
- statsResponse, err := c.adapter.GetServerStats(ctx, serverID, ak, sk)
- if err != nil {
- log.Errorf("Fail to get server stats: %s", err)
- return nil, fmt.Errorf("fail to get server stats: %w", err)
- }
- // 格式化统计结果
- formattedResult := c.formatStatsResult(statsResponse, serverID)
- // 将结果序列化为JSON格式
- resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
- if err != nil {
- log.Errorf("Fail to serialize result: %s", err)
- return nil, fmt.Errorf("fail to serialize result: %w", err)
- }
- // 返回格式化后的结果
- return mcp.NewToolResultText(string(resultJSON)), nil
- }
- // GetName 返回工具的名称标识符
- // 返回值: 工具名称字符串,用于唯一标识该工具
- func (c *CloudpodsServerStatsTool) GetName() string {
- return "cloudpods_get_server_stats"
- }
- // formatStatsResult 格式化虚拟机统计信息的响应结果
- // response: 原始统计响应数据
- // serverID: 虚拟机ID
- // 返回值: 包含统计信息的格式化结果
- func (c *CloudpodsServerStatsTool) formatStatsResult(response *models.ServerStatsResponse, serverID string) map[string]interface{} {
- // 初始化格式化结果结构
- formatted := map[string]interface{}{
- "server_id": serverID,
- "status": response.Status,
- // 添加统计信息
- "stats": map[string]interface{}{
- "cpu_usage": fmt.Sprintf("%.1f%%", response.Data.CPUUsage),
- "memory_usage": fmt.Sprintf("%.1f%%", response.Data.MemUsage),
- "disk_usage": fmt.Sprintf("%.1f%%", response.Data.DiskUsage),
- "network": map[string]interface{}{
- "receive_bps": response.Data.NetBpsRx,
- "transmit_bps": response.Data.NetBpsTx,
- "receive_mbps": fmt.Sprintf("%.2f Mbps", float64(response.Data.NetBpsRx)/(1024*1024)),
- "transmit_mbps": fmt.Sprintf("%.2f Mbps", float64(response.Data.NetBpsTx)/(1024*1024)),
- },
- "updated_at": response.Data.UpdatedAt,
- },
- // 添加原始数据
- "raw_data": map[string]interface{}{
- "cpu_usage": response.Data.CPUUsage,
- "mem_usage": response.Data.MemUsage,
- "disk_usage": response.Data.DiskUsage,
- "net_bps_rx": response.Data.NetBpsRx,
- "net_bps_tx": response.Data.NetBpsTx,
- },
- }
- // 评估虚拟机健康状态
- var healthStatus string
- var healthScore int
- if response.Data.CPUUsage > 90 || response.Data.MemUsage > 90 || response.Data.DiskUsage > 90 {
- healthStatus = "警告"
- healthScore = 1
- } else if response.Data.CPUUsage > 70 || response.Data.MemUsage > 70 || response.Data.DiskUsage > 80 {
- healthStatus = "注意"
- healthScore = 2
- } else {
- healthStatus = "正常"
- healthScore = 3
- }
- // 添加健康状态信息
- formatted["health"] = map[string]interface{}{
- "status": healthStatus,
- "score": healthScore,
- "notes": []string{},
- }
- // 添加健康状态建议
- notes := []string{}
- if response.Data.CPUUsage > 90 {
- notes = append(notes, "CPU使用率过高,建议检查系统负载")
- }
- if response.Data.MemUsage > 90 {
- notes = append(notes, "内存使用率过高,建议释放内存或增加内存")
- }
- if response.Data.DiskUsage > 90 {
- notes = append(notes, "磁盘使用率过高,建议清理磁盘空间")
- }
- formatted["health"].(map[string]interface{})["notes"] = notes
- return formatted
- }
|