| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- // 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"
- "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"
- )
- // CloudpodsServerCreateTool 用于创建Cloudpods虚拟机实例
- type CloudpodsServerCreateTool struct {
- // adapter 用于与 Cloudpods API 进行交互
- adapter *adapters.CloudpodsAdapter
- }
- // NewCloudpodsServerCreateTool 创建一个新的CloudpodsServerCreateTool实例
- // adapter: 用于与Cloudpods API交互的适配器
- // 返回值: CloudpodsServerCreateTool实例指针
- func NewCloudpodsServerCreateTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerCreateTool {
- return &CloudpodsServerCreateTool{
- adapter: adapter,
- }
- }
- // GetTool 定义并返回创建虚拟机工具的元数据
- // 该工具用于创建Cloudpods虚拟机实例,支持指定各种配置参数
- // name: 虚拟机名称 (必填)
- // vcpu_count: CPU核心数 (必填)
- // vmem_size: 内存大小(MB) (必填)
- // image_id: 镜像ID (必填)
- // disk_size: 系统盘大小(GB),不指定则使用镜像默认大小
- // network_id: 网络ID (必填)
- // serversku_id: 套餐ID,指定后将忽略vcpu_count和vmem_size参数
- // password: 虚拟机密码,长度8-30个字符
- // count: 创建数量,默认为1
- // auto_start: 是否自动启动,默认为true
- // billing_type: 计费类型,例如:postpaid、prepaid
- // duration: 包年包月时长,例如:1M、1Y
- // description: 描述信息
- // hostname: 主机名
- // hypervisor: 虚拟化技术,如kvm, esxi等,默认为kvm
- // metadata: 标签列表,格式为JSON字符串,例如:{"key1":"value1","key2":"value2"}
- // secgroup_id: 安全组ID
- // secgroups: 安全组ID列表,多个ID用逗号分隔
- // user_data: 用户自定义启动脚本
- // keypair_id: 秘钥对ID
- // project_id: 项目ID
- // zone_id: 可用区ID
- // region_id: 区域ID
- // disable_delete: 是否开启删除保护,默认为true
- // boot_order: 启动顺序,如cdn
- // data_disks: 数据盘配置,格式为JSON字符串数组,例如:[{"size":100,"disk_type":"data"}]
- // ak: 用户登录cloudpods后获取的access key
- // sk: 用户登录cloudpods后获取的secret key
- func (c *CloudpodsServerCreateTool) GetTool() mcp.Tool {
- return mcp.NewTool(
- "cloudpods_create_server",
- mcp.WithDescription("创建Cloudpods虚拟机实例"),
- mcp.WithString("name", mcp.Required(), mcp.Description("虚拟机名称")),
- mcp.WithString("vcpu_count", mcp.Required(), mcp.Description("CPU核心数")),
- mcp.WithString("vmem_size", mcp.Required(), mcp.Description("内存大小(MB)")),
- mcp.WithString("image_id", mcp.Required(), mcp.Description("镜像ID")),
- mcp.WithString("disk_size", mcp.Description("系统盘大小(GB),不指定则使用镜像默认大小")),
- mcp.WithString("network_id", mcp.Required(), mcp.Description("网络ID")),
- mcp.WithString("serversku_id", mcp.Description("套餐ID,指定后将忽略vcpu_count和vmem_size参数")),
- mcp.WithString("password", mcp.Description("虚拟机密码,长度8-30个字符")),
- mcp.WithString("count", mcp.Description("创建数量,默认为1")),
- mcp.WithString("auto_start", mcp.Description("是否自动启动,默认为true")),
- mcp.WithString("billing_type", mcp.Description("计费类型,例如:postpaid、prepaid")),
- mcp.WithString("duration", mcp.Description("包年包月时长,例如:1M、1Y")),
- mcp.WithString("description", mcp.Description("描述信息")),
- mcp.WithString("hostname", mcp.Description("主机名")),
- mcp.WithString("hypervisor", mcp.Description("虚拟化技术,如kvm, esxi等,默认为kvm")),
- mcp.WithString("metadata", mcp.Description("标签列表,格式为JSON字符串,例如:{\"key1\":\"value1\",\"key2\":\"value2\"}")),
- mcp.WithString("secgroup_id", mcp.Description("安全组ID")),
- mcp.WithString("secgroups", mcp.Description("安全组ID列表,多个ID用逗号分隔")),
- mcp.WithString("user_data", mcp.Description("用户自定义启动脚本")),
- mcp.WithString("keypair_id", mcp.Description("秘钥对ID")),
- mcp.WithString("project_id", mcp.Description("项目ID")),
- mcp.WithString("zone_id", mcp.Description("可用区ID")),
- mcp.WithString("region_id", mcp.Description("区域ID")),
- mcp.WithString("disable_delete", mcp.Description("是否开启删除保护,默认为true")),
- mcp.WithString("boot_order", mcp.Description("启动顺序,如cdn")),
- mcp.WithString("data_disks", mcp.Description("数据盘配置,格式为JSON字符串数组,例如:[{\"size\":100,\"disk_type\":\"data\"}]")),
- mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
- mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
- )
- }
- // Handle 处理创建虚拟机的请求
- // ctx: 上下文,用于控制请求的生命周期
- // req: 包含创建虚拟机所需参数的请求对象
- // 返回值: 包含创建结果的工具结果对象或错误信息
- func (c *CloudpodsServerCreateTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
- // 获取必填参数:虚拟机名称
- name, err := req.RequireString("name")
- if err != nil {
- return nil, err
- }
- // 获取必填参数:镜像ID
- imageID, err := req.RequireString("image_id")
- if err != nil {
- return nil, err
- }
- // 获取必填参数:网络ID
- networkID, err := req.RequireString("network_id")
- if err != nil {
- return nil, err
- }
- // 获取必填参数:CPU核心数并转换为整数
- vcpuCountStr, err := req.RequireString("vcpu_count")
- if err != nil {
- return nil, err
- }
- vcpuCount, err := strconv.ParseInt(vcpuCountStr, 10, 64)
- if err != nil {
- return nil, fmt.Errorf("无效的CPU核心数: %s", vcpuCountStr)
- }
- // 获取必填参数:内存大小并转换为整数
- vmemSizeStr, err := req.RequireString("vmem_size")
- if err != nil {
- return nil, err
- }
- vmemSize, err := strconv.ParseInt(vmemSizeStr, 10, 64)
- if err != nil {
- return nil, fmt.Errorf("无效的内存大小: %s", vmemSizeStr)
- }
- // 获取可选参数:套餐ID
- serverSkuID := req.GetString("serversku_id", "")
- // 获取可选参数:磁盘大小,如果指定则转换为整数
- diskSize := int64(0)
- if diskSizeStr := req.GetString("disk_size", ""); diskSizeStr != "" {
- if parsedSize, err := strconv.ParseInt(diskSizeStr, 10, 64); err == nil && parsedSize > 0 {
- diskSize = parsedSize
- }
- }
- // 获取可选参数:虚拟机密码,并验证长度
- password := req.GetString("password", "")
- if password != "" && (len(password) < 8 || len(password) > 30) {
- return nil, fmt.Errorf("密码长度必须在8-30个字符之间")
- }
- // 获取可选参数:创建数量,默认为1
- count := 1
- if countStr := req.GetString("count", "1"); countStr != "1" {
- if parsedCount, err := strconv.Atoi(countStr); err == nil && parsedCount > 0 {
- count = parsedCount
- }
- }
- // 获取可选参数:是否自动启动,默认为true
- autoStart := true
- if autoStartStr := req.GetString("auto_start", "true"); autoStartStr == "false" {
- autoStart = false
- }
- // 获取可选参数:是否开启删除保护,默认为true
- disableDelete := true
- if disableDeleteStr := req.GetString("disable_delete", "true"); disableDeleteStr == "false" {
- disableDelete = false
- }
- // 获取其他可选参数
- billingType := req.GetString("billing_type", "")
- duration := req.GetString("duration", "")
- description := req.GetString("description", "")
- hostname := req.GetString("hostname", "")
- hypervisor := req.GetString("hypervisor", "")
- secgroupID := req.GetString("secgroup_id", "")
- userData := req.GetString("user_data", "")
- keypairID := req.GetString("keypair_id", "")
- projectID := req.GetString("project_id", "")
- zoneID := req.GetString("zone_id", "")
- regionID := req.GetString("region_id", "")
- bootOrder := req.GetString("boot_order", "")
- // 获取安全组ID列表,并按逗号分割
- var secgroups []string
- if secgroupsStr := req.GetString("secgroups", ""); secgroupsStr != "" {
- secgroups = strings.Split(secgroupsStr, ",")
- }
- // 解析元数据JSON字符串
- metadata := make(map[string]string)
- if metadataStr := req.GetString("metadata", ""); metadataStr != "" {
- if err := json.Unmarshal([]byte(metadataStr), &metadata); err != nil {
- return nil, fmt.Errorf("无效的元数据JSON格式: %w", err)
- }
- }
- // 解析数据盘配置JSON数组
- var dataDisks []models.DiskConfig
- if dataDisksStr := req.GetString("data_disks", ""); dataDisksStr != "" {
- if err := json.Unmarshal([]byte(dataDisksStr), &dataDisks); err != nil {
- return nil, fmt.Errorf("无效的数据盘配置JSON格式: %w", err)
- }
- }
- // 构造创建虚拟机的请求对象
- createRequest := models.CreateServerRequest{
- Name: name,
- VcpuCount: vcpuCount,
- VmemSize: vmemSize,
- ImageId: imageID,
- DiskSize: diskSize,
- NetworkId: networkID,
- ServerskuId: serverSkuID,
- Count: count,
- Password: password,
- AutoStart: autoStart,
- BillingType: billingType,
- Duration: duration,
- Description: description,
- Hostname: hostname,
- Hypervisor: hypervisor,
- Metadata: metadata,
- SecgroupId: secgroupID,
- Secgroups: secgroups,
- UserData: userData,
- KeypairId: keypairID,
- ProjectId: projectID,
- ZoneId: zoneID,
- RegionId: regionID,
- DisableDelete: disableDelete,
- BootOrder: bootOrder,
- DataDisks: dataDisks,
- }
- // 获取访问凭证
- ak := req.GetString("ak", "")
- sk := req.GetString("sk", "")
- // 调用适配器创建虚拟机
- response, err := c.adapter.CreateServer(ctx, createRequest, ak, sk)
- if err != nil {
- log.Errorf("Fail to create server: %s", err)
- return nil, fmt.Errorf("fail to create server: %w", err)
- }
- // 格式化创建结果
- formattedResult := c.formatCreateResult(response, &createRequest)
- // 将结果序列化为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 *CloudpodsServerCreateTool) GetName() string {
- return "cloudpods_create_server"
- }
- // formatCreateResult 格式化创建虚拟机的响应结果
- // response: 原始的创建虚拟机响应数据
- // request: 原始的创建虚拟机请求数据
- // 返回值: 格式化后的结果,包含创建信息、结果详情和摘要
- func (c *CloudpodsServerCreateTool) formatCreateResult(response *models.CreateServerResponse, request *models.CreateServerRequest) map[string]interface{} {
- // 初始化格式化结果结构
- formatted := map[string]interface{}{
- // 创建请求的基本信息
- "create_info": map[string]interface{}{
- "name": request.Name,
- "vcpu_count": request.VcpuCount,
- "vmem_size": request.VmemSize,
- "image_id": request.ImageId,
- "disk_size": request.DiskSize,
- "network_id": request.NetworkId,
- "serversku_id": request.ServerskuId,
- "count": request.Count,
- "auto_start": request.AutoStart,
- "billing_type": request.BillingType,
- "duration": request.Duration,
- "description": request.Description,
- "hostname": request.Hostname,
- "hypervisor": request.Hypervisor,
- "secgroup_id": request.SecgroupId,
- "keypair_id": request.KeypairId,
- "project_id": request.ProjectId,
- "zone_id": request.ZoneId,
- "region_id": request.RegionId,
- "disable_delete": request.DisableDelete,
- "boot_order": request.BootOrder,
- },
- // 创建响应的结果信息
- "result": map[string]interface{}{
- "status": response.Status,
- "message": response.Message,
- "servers": make([]map[string]interface{}, 0, len(response.Data.Servers)),
- },
- }
- // 遍历创建的虚拟机列表,构造每个虚拟机的详细信息
- for _, server := range response.Data.Servers {
- serverInfo := map[string]interface{}{
- "id": server.ID,
- "name": server.Name,
- "status": server.Status,
- "task_id": server.TaskID,
- }
- formatted["result"].(map[string]interface{})["servers"] = append(
- formatted["result"].(map[string]interface{})["servers"].([]map[string]interface{}),
- serverInfo,
- )
- }
- // 构造摘要信息
- formatted["summary"] = map[string]interface{}{
- "requested_count": request.Count, // 请求创建的虚拟机数量
- "created_count": len(response.Data.Servers), // 实际创建的虚拟机数量
- "success": response.Status == 200, // 创建是否成功
- }
- return formatted
- }
|