cloudpods_serverskus_tool.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package tools
  15. import (
  16. "context"
  17. "encoding/json"
  18. "fmt"
  19. "strconv"
  20. "strings"
  21. "github.com/mark3labs/mcp-go/mcp"
  22. "yunion.io/x/log"
  23. "yunion.io/x/onecloud/pkg/mcp-server/adapters"
  24. "yunion.io/x/onecloud/pkg/mcp-server/models"
  25. )
  26. // CloudpodsServerSkusTool 用于查询Cloudpods主机套餐规格列表的工具
  27. type CloudpodsServerSkusTool struct {
  28. // adapter 用于与Cloudpods API进行交互
  29. adapter *adapters.CloudpodsAdapter
  30. }
  31. // NewCloudpodsServerSkusTool 创建一个新的CloudpodsServerSkusTool实例
  32. //
  33. // 参数:
  34. // - adapter: 用于与Cloudpods API交互的适配器
  35. //
  36. // 返回值:
  37. // - *CloudpodsServerSkusTool: CloudpodsServerSkusTool实例指针
  38. func NewCloudpodsServerSkusTool(adapter *adapters.CloudpodsAdapter) *CloudpodsServerSkusTool {
  39. return &CloudpodsServerSkusTool{
  40. adapter: adapter,
  41. }
  42. }
  43. // GetTool 定义并返回查询主机套餐规格列表工具的元数据
  44. //
  45. // 工具用途:
  46. //
  47. // 查询Cloudpods主机套餐规格列表,获取虚拟机规格信息
  48. //
  49. // 参数说明:
  50. // - limit: 返回结果数量限制,默认为20
  51. // - offset: 返回结果偏移量,默认为0
  52. // - search: 搜索关键词,可以按规格名称搜索
  53. // - cloudregion_ids: 云区域ID,多个用逗号分隔
  54. // - zone_ids: 可用区ID,多个用逗号分隔
  55. // - cpu_core_count: CPU核心数,多个用逗号分隔,如:1,2,4,8
  56. // - memory_size_mb: 内存大小MB,多个用逗号分隔,如:1024,2048,4096
  57. // - providers: 云平台提供商,多个用逗号分隔,如:OneCloud,Aliyun,Huawei
  58. // - cpu_arch: CPU架构,多个用逗号分隔,如:x86,arm
  59. // - ak: 用户登录cloudpods后获取的access key
  60. // - sk: 用户登录cloudpods后获取的secret key
  61. func (c *CloudpodsServerSkusTool) GetTool() mcp.Tool {
  62. return mcp.NewTool(
  63. "cloudpods_list_serverskus",
  64. mcp.WithDescription("查询Cloudpods主机套餐规格列表,获取虚拟机规格信息"),
  65. mcp.WithString("limit", mcp.Description("返回结果数量限制,默认为20")),
  66. mcp.WithString("offset", mcp.Description("返回结果偏移量,默认为0")),
  67. mcp.WithString("search", mcp.Description("搜索关键词,可以按规格名称搜索")),
  68. mcp.WithString("cloudregion_ids", mcp.Description("云区域ID,多个用逗号分隔")),
  69. mcp.WithString("zone_ids", mcp.Description("可用区ID,多个用逗号分隔")),
  70. mcp.WithString("cpu_core_count", mcp.Description("CPU核心数,多个用逗号分隔,如:1,2,4,8")),
  71. mcp.WithString("memory_size_mb", mcp.Description("内存大小MB,多个用逗号分隔,如:1024,2048,4096")),
  72. mcp.WithString("providers", mcp.Description("云平台提供商,多个用逗号分隔,如:OneCloud,Aliyun,Huawei")),
  73. mcp.WithString("cpu_arch", mcp.Description("CPU架构,多个用逗号分隔,如:x86,arm")),
  74. mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
  75. mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
  76. )
  77. }
  78. // Handle 处理查询主机套餐规格列表的请求
  79. //
  80. // 参数:
  81. // - ctx: 控制生命周期的上下文
  82. // - req: 包含查询参数的请求对象
  83. //
  84. // 返回值:
  85. // - *mcp.CallToolResult: 包含主机套餐规格列表的响应对象
  86. // - error: 可能的错误信息
  87. func (c *CloudpodsServerSkusTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  88. // 获取可选参数:返回结果数量限制,如果指定则转换为整数
  89. limit := 20
  90. if limitStr := req.GetString("limit", ""); limitStr != "" {
  91. if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 {
  92. limit = parsedLimit
  93. }
  94. }
  95. // 获取可选参数:结果偏移量,如果指定则转换为整数
  96. offset := 0
  97. if offsetStr := req.GetString("offset", ""); offsetStr != "" {
  98. if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 {
  99. offset = parsedOffset
  100. }
  101. }
  102. // 获取可选参数:搜索关键词
  103. search := req.GetString("search", "")
  104. // 获取可选参数:云区域ID列表
  105. var cloudregionIds []string
  106. if cloudregionIdsStr := req.GetString("cloudregion_ids", ""); cloudregionIdsStr != "" {
  107. cloudregionIds = strings.Split(cloudregionIdsStr, ",")
  108. for i, id := range cloudregionIds {
  109. cloudregionIds[i] = strings.TrimSpace(id)
  110. }
  111. }
  112. // 获取可选参数:可用区ID列表
  113. var zoneIds []string
  114. if zoneIdsStr := req.GetString("zone_ids", ""); zoneIdsStr != "" {
  115. zoneIds = strings.Split(zoneIdsStr, ",")
  116. for i, id := range zoneIds {
  117. zoneIds[i] = strings.TrimSpace(id)
  118. }
  119. }
  120. // 获取可选参数:CPU核心数列表
  121. var cpuCoreCount []string
  122. if cpuCoreCountStr := req.GetString("cpu_core_count", ""); cpuCoreCountStr != "" {
  123. cpuCoreCount = strings.Split(cpuCoreCountStr, ",")
  124. for i, count := range cpuCoreCount {
  125. cpuCoreCount[i] = strings.TrimSpace(count)
  126. }
  127. }
  128. // 获取可选参数:内存大小列表(MB)
  129. var memorySizeMB []string
  130. if memorySizeMBStr := req.GetString("memory_size_mb", ""); memorySizeMBStr != "" {
  131. memorySizeMB = strings.Split(memorySizeMBStr, ",")
  132. for i, size := range memorySizeMB {
  133. memorySizeMB[i] = strings.TrimSpace(size)
  134. }
  135. }
  136. // 获取可选参数:云平台提供商列表
  137. var providers []string
  138. if providersStr := req.GetString("providers", ""); providersStr != "" {
  139. providers = strings.Split(providersStr, ",")
  140. for i, provider := range providers {
  141. providers[i] = strings.TrimSpace(provider)
  142. }
  143. }
  144. // 获取可选参数:CPU架构列表
  145. var cpuArch []string
  146. if cpuArchStr := req.GetString("cpu_arch", ""); cpuArchStr != "" {
  147. cpuArch = strings.Split(cpuArchStr, ",")
  148. for i, arch := range cpuArch {
  149. cpuArch[i] = strings.TrimSpace(arch)
  150. }
  151. }
  152. ak := req.GetString("ak", "")
  153. sk := req.GetString("sk", "")
  154. // 调用适配器查询主机套餐规格列表
  155. skusResponse, err := c.adapter.ListServerSkus(ctx, limit, offset, search, cloudregionIds, zoneIds, cpuCoreCount, memorySizeMB, providers, cpuArch, ak, sk)
  156. if err != nil {
  157. log.Errorf("Fail to query server skus: %s", err)
  158. return nil, fmt.Errorf("fail to query server skus: %w", err)
  159. }
  160. // 格式化查询结果
  161. formattedResult := c.formatServerSkusResult(skusResponse, limit, offset, search, cloudregionIds, zoneIds, cpuCoreCount, memorySizeMB, providers, cpuArch)
  162. // 将结果序列化为JSON格式
  163. resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
  164. if err != nil {
  165. log.Errorf("Fail to serialize result: %s", err)
  166. return nil, fmt.Errorf("fail to serialize result: %w", err)
  167. }
  168. return mcp.NewToolResultText(string(resultJSON)), nil
  169. }
  170. // GetName 返回工具的名称标识符
  171. //
  172. // 返回值:
  173. // - string: 工具名称字符串,用于唯一标识该工具
  174. func (c *CloudpodsServerSkusTool) GetName() string {
  175. return "cloudpods_list_serverskus"
  176. }
  177. // formatServerSkusResult 格式化主机套餐规格列表的响应结果
  178. //
  179. // 参数:
  180. // - response: 原始主机套餐规格列表响应数据
  181. // - limit: 查询限制数量
  182. // - offset: 查询偏移量
  183. // - search: 搜索关键词
  184. // - cloudregionIds: 云区域ID列表
  185. // - zoneIds: 可用区ID列表
  186. // - cpuCoreCount: CPU核心数列表
  187. // - memorySizeMB: 内存大小列表(MB)
  188. // - providers: 云平台提供商列表
  189. // - cpuArch: CPU架构列表
  190. //
  191. // 返回值:
  192. // - map[string]interface{}: 包含主机套餐规格列表的格式化结果
  193. func (c *CloudpodsServerSkusTool) formatServerSkusResult(
  194. response *models.ServerSkuListResponse,
  195. limit, offset int,
  196. search string,
  197. cloudregionIds, zoneIds, cpuCoreCount, memorySizeMB, providers, cpuArch []string,
  198. ) map[string]interface{} {
  199. // 初始化格式化结果结构
  200. formatted := map[string]interface{}{
  201. "query_info": map[string]interface{}{
  202. "limit": limit,
  203. "offset": offset,
  204. "search": search,
  205. "cloudregion_ids": cloudregionIds,
  206. "zone_ids": zoneIds,
  207. "cpu_core_count": cpuCoreCount,
  208. "memory_size_mb": memorySizeMB,
  209. "providers": providers,
  210. "cpu_arch": cpuArch,
  211. "total": response.Total,
  212. "count": len(response.Serverskus),
  213. },
  214. "serverskus": make([]map[string]interface{}, 0, len(response.Serverskus)),
  215. }
  216. // 遍历主机套餐列表,构造每个主机套餐的详细信息
  217. for _, sku := range response.Serverskus {
  218. skuInfo := map[string]interface{}{
  219. "id": sku.Id,
  220. "name": sku.Name,
  221. "description": sku.Description,
  222. "status": sku.Status,
  223. "enabled": sku.Enabled,
  224. "provider": sku.Provider,
  225. "cloud_env": sku.CloudEnv,
  226. "cloudregion": sku.Cloudregion,
  227. "cloudregion_id": sku.CloudregionId,
  228. "zone": sku.Zone,
  229. "zone_id": sku.ZoneId,
  230. "zone_ext_id": sku.ZoneExtId,
  231. "cpu_core_count": sku.CpuCoreCount,
  232. "memory_size_mb": sku.MemorySizeMB,
  233. "cpu_arch": sku.CpuArch,
  234. "instance_type_family": sku.InstanceTypeFamily,
  235. "instance_type_category": sku.InstanceTypeCategory,
  236. "local_category": sku.LocalCategory,
  237. "sys_disk_type": sku.SysDiskType,
  238. "sys_disk_min_size_gb": sku.SysDiskMinSizeGB,
  239. "sys_disk_max_size_gb": sku.SysDiskMaxSizeGB,
  240. "sys_disk_resizable": sku.SysDiskResizable,
  241. "data_disk_types": sku.DataDiskTypes,
  242. "data_disk_max_count": sku.DataDiskMaxCount,
  243. "attached_disk_count": sku.AttachedDiskCount,
  244. "attached_disk_size_gb": sku.AttachedDiskSizeGB,
  245. "attached_disk_type": sku.AttachedDiskType,
  246. "nic_type": sku.NicType,
  247. "nic_max_count": sku.NicMaxCount,
  248. "gpu_attachable": sku.GpuAttachable,
  249. "gpu_count": sku.GpuCount,
  250. "gpu_max_count": sku.GpuMaxCount,
  251. "gpu_spec": sku.GpuSpec,
  252. "os_name": sku.OsName,
  253. "postpaid_status": sku.PostpaidStatus,
  254. "prepaid_status": sku.PrepaidStatus,
  255. "total_guest_count": sku.TotalGuestCount,
  256. "external_id": sku.ExternalId,
  257. "source": sku.Source,
  258. "is_emulated": sku.IsEmulated,
  259. "region": sku.Region,
  260. "region_id": sku.RegionId,
  261. "region_ext_id": sku.RegionExtId,
  262. "region_external_id": sku.RegionExternalId,
  263. "md5": sku.Md5,
  264. "metadata": sku.Metadata,
  265. "progress": sku.Progress,
  266. "can_delete": sku.CanDelete,
  267. "can_update": sku.CanUpdate,
  268. "update_version": sku.UpdateVersion,
  269. "created_at": sku.CreatedAt,
  270. "updated_at": sku.UpdatedAt,
  271. "imported_at": sku.ImportedAt,
  272. }
  273. formatted["serverskus"] = append(formatted["serverskus"].([]map[string]interface{}), skuInfo)
  274. }
  275. // 构造摘要信息
  276. formatted["summary"] = map[string]interface{}{
  277. "total_serverskus": response.Total,
  278. "returned_count": len(response.Serverskus),
  279. "has_more": response.Total > int64(offset+len(response.Serverskus)),
  280. "next_offset": offset + len(response.Serverskus),
  281. }
  282. return formatted
  283. }