Files
cloudpods/pkg/mcp-server/tools/cloudpods_server_operations_tool.go
2026-07-17 00:26:47 +08:00

525 lines
20 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"
"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"
)
// CloudpodsServerStartTool 用于启动指定的Cloudpods虚拟机实例
type CloudpodsServerStartTool struct {
adapter *adapters.CloudpodsAdapter
}
// NewCloudpodsServerStartTool 创建一个新的CloudpodsServerStartTool实例
func NewCloudpodsServerStartTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerStartTool {
return &CloudpodsServerStartTool{
adapter: adapter,
}
}
// GetTool 返回启动虚拟机工具的定义,包括参数和描述
func (c *CloudpodsServerStartTool) GetTool() mcp.Tool {
return mcp.NewTool(
"cloudpods_start_server",
mcp.WithDescription("启动指定的Cloudpods虚拟机实例。用户要求开机/启动时必须调用本工具真正执行启动仅调用cloudpods_list_servers 查询不算完成。若尚不知 server_id先用 cloudpods_list_servers可用 search定位拿到 id 后立即调用本工具,不要只查询就结束。"),
mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID来自 cloudpods_list_servers 返回的 id 字段")),
mcp.WithString("auto_prepaid", mcp.Description("按量机器自动转换为包年包月默认为false")),
mcp.WithString("qemu_version", mcp.Description("指定启动虚拟机的Qemu版本可选值2.12.1, 4.2.0仅适用于KVM虚拟机")),
mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
)
}
// Handle 处理启动虚拟机的请求,调用适配器执行启动操作并返回结果
func (c *CloudpodsServerStartTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// 从请求中获取必需的 server_id 参数
serverID, err := req.RequireString("server_id")
if err != nil {
return nil, err
}
// 解析 auto_prepaid 参数,决定是否自动转换为包年包月
autoPrepaid := false
if autoPrepaidStr := req.GetString("auto_prepaid", "false"); autoPrepaidStr == "true" {
autoPrepaid = true
}
// 获取 qemu_version 参数,用于指定启动虚拟机的 Qemu 版本
qemuVersion := req.GetString("qemu_version", "")
// 构造启动虚拟机的请求参数
startReq := models.ServerStartRequest{
AutoPrepaid: autoPrepaid,
QemuVersion: qemuVersion,
}
// 获取认证所需的 access key 和 secret key
ak := req.GetString("ak", "")
sk := req.GetString("sk", "")
// 调用适配器的 StartServer 方法执行启动操作
response, err := c.adapter.StartServer(ctx, serverID, startReq, ak, sk)
if err != nil {
log.Errorf("Fail to start server: %s", err)
return nil, fmt.Errorf("fail to start server: %w", err)
}
// 构造返回结果包含任务ID、成功状态和状态信息
result := map[string]interface{}{
"server_id": serverID,
"operation": "start",
"task_id": response.TaskId,
"success": response.Success,
"status": response.Status,
}
// 如果有错误信息,则添加到结果中
if response.Error != "" {
result["error"] = response.Error
}
// 将结果序列化为 JSON 格式
resultJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
return nil, fmt.Errorf("序列化结果失败: %w", err)
}
// 返回序列化后的结果
return mcp.NewToolResultText(string(resultJSON)), nil
}
// GetName 返回启动虚拟机工具的名称
func (c *CloudpodsServerStartTool) GetName() string {
return "cloudpods_start_server"
}
// CloudpodsServerStopTool 用于停止指定的Cloudpods虚拟机实例
type CloudpodsServerStopTool struct {
adapter *adapters.CloudpodsAdapter
}
// NewCloudpodsServerStopTool 创建一个新的CloudpodsServerStopTool实例
func NewCloudpodsServerStopTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerStopTool {
return &CloudpodsServerStopTool{
adapter: adapter,
}
}
// GetTool 返回停止虚拟机工具的定义,包括参数和描述
func (c *CloudpodsServerStopTool) GetTool() mcp.Tool {
return mcp.NewTool(
"cloudpods_stop_server",
mcp.WithDescription("停止指定的Cloudpods虚拟机实例。用户要求关机/停止时必须调用本工具真正执行停止,仅调用 cloudpods_list_servers 查询不算完成。若尚不知 server_id先用 cloudpods_list_servers可用 search定位拿到 id 后立即调用本工具,不要只查询就结束,也不要再次向用户确认。"),
mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID来自 cloudpods_list_servers 返回的 id 字段")),
mcp.WithString("is_force", mcp.Description("是否强制停止默认为false")),
mcp.WithString("stop_charging", mcp.Description("是否关机停止计费默认为false")),
mcp.WithString("timeout_secs", mcp.Description("关机等待时间如果是强制关机则等待时间为0如果不设置默认为30秒")),
mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
)
}
// Handle 处理停止虚拟机的请求,调用适配器执行停止操作并返回结果
func (c *CloudpodsServerStopTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// 从请求中获取必需的 server_id 参数
serverID, err := req.RequireString("server_id")
if err != nil {
return nil, err
}
// 解析 is_force 参数,决定是否强制停止虚拟机
isForce := false
if isForceStr := req.GetString("is_force", "false"); isForceStr == "true" {
isForce = true
}
// 解析 stop_charging 参数,决定是否停止计费
stopCharging := false
if stopChargingStr := req.GetString("stop_charging", "false"); stopChargingStr == "true" {
stopCharging = true
}
// 解析 timeout_secs 参数,设置停止操作的超时时间
timeoutSecs := int64(0)
if timeoutSecsStr := req.GetString("timeout_secs", ""); timeoutSecsStr != "" {
if parsed, err := strconv.ParseInt(timeoutSecsStr, 10, 64); err == nil && parsed > 0 {
timeoutSecs = parsed
}
}
// 构造停止虚拟机的请求参数
stopReq := models.ServerStopRequest{
IsForce: isForce,
StopCharging: stopCharging,
TimeoutSecs: timeoutSecs,
}
// 获取认证所需的 access key 和 secret key
ak := req.GetString("ak", "")
sk := req.GetString("sk", "")
// 调用适配器的 StopServer 方法执行停止操作
response, err := c.adapter.StopServer(ctx, serverID, stopReq, ak, sk)
if err != nil {
log.Errorf("Fail to stop server: %s", err)
return nil, fmt.Errorf("fail to stop server: %w", err)
}
// 构造返回结果包含任务ID、成功状态和状态信息
result := map[string]interface{}{
"server_id": serverID,
"operation": "stop",
"task_id": response.TaskId,
"success": response.Success,
"status": response.Status,
}
// 如果有错误信息,则添加到结果中
if response.Error != "" {
result["error"] = response.Error
}
// 将结果序列化为 JSON 格式
resultJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
return nil, fmt.Errorf("序列化结果失败: %w", err)
}
// 返回序列化后的结果
return mcp.NewToolResultText(string(resultJSON)), nil
}
// GetName 返回停止虚拟机工具的名称
func (c *CloudpodsServerStopTool) GetName() string {
return "cloudpods_stop_server"
}
// CloudpodsServerRestartTool 用于重启指定的Cloudpods虚拟机实例
type CloudpodsServerRestartTool struct {
adapter *adapters.CloudpodsAdapter
}
// NewCloudpodsServerRestartTool 创建一个新的CloudpodsServerRestartTool实例
func NewCloudpodsServerRestartTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerRestartTool {
return &CloudpodsServerRestartTool{
adapter: adapter,
}
}
// GetTool 返回重启虚拟机工具的定义,包括参数和描述
func (c *CloudpodsServerRestartTool) GetTool() mcp.Tool {
return mcp.NewTool(
"cloudpods_restart_server",
mcp.WithDescription("重启指定的Cloudpods虚拟机实例。用户要求重启时必须调用本工具真正执行重启仅调用 cloudpods_list_servers 查询不算完成。若尚不知 server_id先用 cloudpods_list_servers可用 search定位拿到 id 后立即调用本工具,不要只查询就结束,也不要再次向用户确认。"),
mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID来自 cloudpods_list_servers 返回的 id 字段")),
mcp.WithString("is_force", mcp.Description("是否强制重启默认为false")),
mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
)
}
// Handle 处理重启虚拟机的请求,调用适配器执行重启操作并返回结果
func (c *CloudpodsServerRestartTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// 从请求中获取必需的 server_id 参数
serverID, err := req.RequireString("server_id")
if err != nil {
return nil, err
}
// 解析 is_force 参数,决定是否强制重启虚拟机
isForce := false
if isForceStr := req.GetString("is_force", "false"); isForceStr == "true" {
isForce = true
}
// 构造重启虚拟机的请求参数
restartReq := models.ServerRestartRequest{
IsForce: isForce,
}
// 获取认证所需的 access key 和 secret key
ak := req.GetString("ak", "")
sk := req.GetString("sk", "")
// 调用适配器的 RestartServer 方法执行重启操作
response, err := c.adapter.RestartServer(ctx, serverID, restartReq, ak, sk)
if err != nil {
log.Errorf("Fail to query restart server: %s", err)
return nil, fmt.Errorf("fail to restart server: %w", err)
}
// 构造返回结果包含任务ID、成功状态和状态信息
result := map[string]interface{}{
"server_id": serverID,
"operation": "restart",
"task_id": response.TaskId,
"success": response.Success,
"status": response.Status,
}
// 如果有错误信息,则添加到结果中
if response.Error != "" {
result["error"] = response.Error
}
// 将结果序列化为 JSON 格式
resultJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
return nil, fmt.Errorf("序列化结果失败: %w", err)
}
// 返回序列化后的结果
return mcp.NewToolResultText(string(resultJSON)), nil
}
// GetName 返回重启虚拟机工具的名称
func (c *CloudpodsServerRestartTool) GetName() string {
return "cloudpods_restart_server"
}
// CloudpodsServerResetPasswordTool 用于重置指定Cloudpods虚拟机的登录密码
type CloudpodsServerResetPasswordTool struct {
adapter *adapters.CloudpodsAdapter
}
// NewCloudpodsServerResetPasswordTool 创建一个新的CloudpodsServerResetPasswordTool实例
func NewCloudpodsServerResetPasswordTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerResetPasswordTool {
return &CloudpodsServerResetPasswordTool{
adapter: adapter,
}
}
// GetTool 返回重置虚拟机密码工具的定义,包括参数和描述
func (c *CloudpodsServerResetPasswordTool) GetTool() mcp.Tool {
return mcp.NewTool(
"cloudpods_reset_server_password",
mcp.WithDescription("重置指定Cloudpods虚拟机的登录密码。用户要求重置密码时必须调用本工具真正执行仅调用 cloudpods_list_servers 查询不算完成。若尚不知 server_id先用 cloudpods_list_servers 定位,拿到 id 后立即调用本工具。"),
mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID来自 cloudpods_list_servers 返回的 id 字段")),
mcp.WithString("password", mcp.Required(), mcp.Description("新密码长度8-30个字符")),
mcp.WithString("reset_password", mcp.Description("是否重置密码默认为true")),
mcp.WithString("auto_start", mcp.Description("重置后是否自动启动默认为true")),
mcp.WithString("username", mcp.Description("用户名,可选,默认为空")),
mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
)
}
// Handle 处理重置虚拟机密码的请求,调用适配器执行密码重置操作并返回结果
func (c *CloudpodsServerResetPasswordTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// 从请求中获取必需的 server_id 参数
serverID, err := req.RequireString("server_id")
if err != nil {
return nil, err
}
// 从请求中获取必需的 password 参数,并验证其长度
password, err := req.RequireString("password")
if err != nil {
return nil, err
}
if len(password) < 8 || len(password) > 30 {
return nil, fmt.Errorf("密码长度必须在8-30个字符之间")
}
// 解析 reset_password 参数,决定是否重置密码
resetPassword := true
if resetPasswordStr := req.GetString("reset_password", "true"); resetPasswordStr == "false" {
resetPassword = false
}
// 解析 auto_start 参数,决定重置密码后是否自动启动虚拟机
autoStart := true
if autoStartStr := req.GetString("auto_start", "true"); autoStartStr == "false" {
autoStart = false
}
// 获取 username 参数,可选
username := req.GetString("username", "")
// 构造重置虚拟机密码的请求参数
resetPasswordReq := models.ServerResetPasswordRequest{
Password: password,
ResetPassword: resetPassword,
AutoStart: autoStart,
Username: username,
}
// 获取认证所需的 access key 和 secret key
ak := req.GetString("ak", "")
sk := req.GetString("sk", "")
// 调用适配器的 ResetServerPassword 方法执行密码重置操作
response, err := c.adapter.ResetServerPassword(ctx, serverID, resetPasswordReq, ak, sk)
if err != nil {
log.Errorf("Fail to reset server password: %s", err)
return nil, fmt.Errorf("fail to reset server password: %w", err)
}
// 构造返回结果包含任务ID、成功状态和状态信息
result := map[string]interface{}{
"server_id": serverID,
"operation": "reset-password",
"task_id": response.TaskId,
"success": response.Success,
"status": response.Status,
}
// 如果有错误信息,则添加到结果中
if response.Error != "" {
result["error"] = response.Error
}
// 将结果序列化为 JSON 格式
resultJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
return nil, fmt.Errorf("序列化结果失败: %w", err)
}
// 返回序列化后的结果
return mcp.NewToolResultText(string(resultJSON)), nil
}
// GetName 返回重置虚拟机密码工具的名称
func (c *CloudpodsServerResetPasswordTool) GetName() string {
return "cloudpods_reset_server_password"
}
// CloudpodsServerDeleteTool 用于删除指定的Cloudpods虚拟机实例
type CloudpodsServerDeleteTool struct {
adapter *adapters.CloudpodsAdapter
}
// NewCloudpodsServerDeleteTool 创建一个新的CloudpodsServerDeleteTool实例
func NewCloudpodsServerDeleteTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerDeleteTool {
return &CloudpodsServerDeleteTool{
adapter: adapter,
}
}
// GetTool 返回删除虚拟机工具的定义,包括参数和描述
func (c *CloudpodsServerDeleteTool) GetTool() mcp.Tool {
return mcp.NewTool(
"cloudpods_delete_server",
mcp.WithDescription("删除指定的Cloudpods虚拟机实例。用户要求删除时必须调用本工具真正执行删除仅调用 cloudpods_list_servers 查询不算完成。若尚不知 server_id先用 cloudpods_list_servers 定位,拿到 id 后立即调用本工具。"),
mcp.WithString("server_id", mcp.Required(), mcp.Description("虚拟机ID来自 cloudpods_list_servers 返回的 id 字段")),
mcp.WithString("override_pending_delete", mcp.Description("是否强制删除包括在回收站中的实例默认为false")),
mcp.WithString("purge", mcp.Description("是否仅删除本地资源默认为false")),
mcp.WithString("delete_snapshots", mcp.Description("是否删除快照默认为false")),
mcp.WithString("delete_eip", mcp.Description("是否删除关联的EIP默认为false")),
mcp.WithString("delete_disks", mcp.Description("是否删除关联的数据盘默认为false")),
mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
)
}
// Handle 处理删除虚拟机的请求,调用适配器执行删除操作并返回结果
func (c *CloudpodsServerDeleteTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// 从请求中获取必需的 server_id 参数
serverID, err := req.RequireString("server_id")
if err != nil {
return nil, err
}
// 解析 override_pending_delete 参数,决定是否强制删除(包括在回收站中的实例)
overridePendingDelete := false
if overrideStr := req.GetString("override_pending_delete", "false"); overrideStr == "true" {
overridePendingDelete = true
}
// 解析 purge 参数,决定是否仅删除本地资源
purge := false
if purgeStr := req.GetString("purge", "false"); purgeStr == "true" {
purge = true
}
// 解析 delete_snapshots 参数,决定是否删除快照
deleteSnapshots := false
if deleteSnapshotsStr := req.GetString("delete_snapshots", "false"); deleteSnapshotsStr == "true" {
deleteSnapshots = true
}
// 解析 delete_eip 参数决定是否删除关联的EIP
deleteEip := false
if deleteEipStr := req.GetString("delete_eip", "false"); deleteEipStr == "true" {
deleteEip = true
}
// 解析 delete_disks 参数,决定是否删除关联的数据盘
deleteDisks := false
if deleteDisksStr := req.GetString("delete_disks", "false"); deleteDisksStr == "true" {
deleteDisks = true
}
// 构造删除虚拟机的请求参数
deleteReq := models.ServerDeleteRequest{
OverridePendingDelete: overridePendingDelete,
Purge: purge,
DeleteSnapshots: deleteSnapshots,
DeleteEip: deleteEip,
DeleteDisks: deleteDisks,
}
// 获取认证所需的 access key 和 secret key
ak := req.GetString("ak", "")
sk := req.GetString("sk", "")
// 调用适配器的 DeleteServer 方法执行删除操作
response, err := c.adapter.DeleteServer(ctx, serverID, deleteReq, ak, sk)
if err != nil {
log.Errorf("Fail to delete server: %s", err)
return nil, fmt.Errorf("fail to delete server: %w", err)
}
// 构造返回结果包含任务ID、成功状态和状态信息
result := map[string]interface{}{
"server_id": serverID,
"operation": "delete",
"task_id": response.TaskId,
"success": response.Success,
"status": response.Status,
}
// 如果有错误信息,则添加到结果中
if response.Error != "" {
result["error"] = response.Error
}
// 将结果序列化为 JSON 格式
resultJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
return nil, fmt.Errorf("序列化结果失败: %w", err)
}
// 返回序列化后的结果
return mcp.NewToolResultText(string(resultJSON)), nil
}
// GetName 返回删除虚拟机工具的名称
func (c *CloudpodsServerDeleteTool) GetName() string {
return "cloudpods_delete_server"
}