cloudpods_networks_tool.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. "github.com/mark3labs/mcp-go/mcp"
  21. "yunion.io/x/log"
  22. "yunion.io/x/onecloud/pkg/mcp-server/adapters"
  23. "yunion.io/x/onecloud/pkg/mcp-server/models"
  24. )
  25. // CloudpodsNetworksTool 是一个用于查询 Cloudpods 网络列表的工具
  26. type CloudpodsNetworksTool struct {
  27. // adapter 用于与 Cloudpods API 进行交互
  28. adapter *adapters.CloudpodsAdapter
  29. }
  30. // NewCloudpodsNetworksTool 创建一个新的 CloudpodsNetworksTool 实例
  31. // adapter: 用于与 Cloudpods API 进行交互的适配器
  32. // 返回值: 指向新创建的 CloudpodsNetworksTool 实例的指针
  33. func NewCloudpodsNetworksTool(adapter *adapters.CloudpodsAdapter) *CloudpodsNetworksTool {
  34. return &CloudpodsNetworksTool{
  35. adapter: adapter,
  36. }
  37. }
  38. // GetTool 定义并返回网络列表查询工具的元数据
  39. // 该工具用于查询Cloudpods中的IP子网列表,获取网络配置信息
  40. // 支持的参数包括:
  41. // - limit: 返回结果数量限制,默认为20
  42. // - offset: 返回结果偏移量,默认为0
  43. // - search: 搜索关键词,可以按网络名称搜索
  44. // - vpc_id: 过滤指定VPC的网络资源
  45. // - ak: 用户登录cloudpods后获取的access key
  46. // - sk: 用户登录cloudpods后获取的secret key
  47. func (c *CloudpodsNetworksTool) GetTool() mcp.Tool {
  48. return mcp.NewTool(
  49. "cloudpods_list_networks",
  50. mcp.WithDescription("查询Cloudpods IP子网列表,获取网络配置信息"),
  51. mcp.WithString("limit", mcp.Description("返回结果数量限制,默认为20")),
  52. mcp.WithString("offset", mcp.Description("返回结果偏移量,默认为0")),
  53. mcp.WithString("search", mcp.Description("搜索关键词,可以按网络名称搜索")),
  54. mcp.WithString("vpc_id", mcp.Description("过滤指定VPC的网络资源")),
  55. mcp.WithString("ak", mcp.Description("用户登录cloudpods后获取的access key")),
  56. mcp.WithString("sk", mcp.Description("用户登录cloudpods后获取的secret key")),
  57. )
  58. }
  59. // Handle 处理网络列表查询请求
  60. // ctx: 控制请求生命周期的上下文
  61. // req: 包含查询参数的请求对象
  62. // 返回值: 包含查询结果的工具结果对象或错误信息
  63. func (c *CloudpodsNetworksTool) Handle(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
  64. // 设置默认查询限制为20
  65. limit := 20
  66. if limitStr := req.GetString("limit", ""); limitStr != "" {
  67. // 解析limit参数,如果解析成功且大于0,则使用解析后的值
  68. if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 {
  69. limit = parsedLimit
  70. }
  71. }
  72. // 设置默认偏移量为0
  73. offset := 0
  74. if offsetStr := req.GetString("offset", ""); offsetStr != "" {
  75. // 解析offset参数,如果解析成功且大于等于0,则使用解析后的值
  76. if parsedOffset, err := strconv.Atoi(offsetStr); err == nil && parsedOffset >= 0 {
  77. offset = parsedOffset
  78. }
  79. }
  80. // 获取搜索关键词和VPC ID参数
  81. search := req.GetString("search", "")
  82. vpcId := req.GetString("vpc_id", "")
  83. // 获取访问凭证
  84. ak := req.GetString("ak", "")
  85. sk := req.GetString("sk", "")
  86. // 调用适配器获取网络列表
  87. networksResponse, err := c.adapter.ListNetworks(ctx, limit, offset, search, vpcId, ak, sk)
  88. if err != nil {
  89. log.Errorf("Fail to query network: %s", err)
  90. return nil, fmt.Errorf("fail to query network: %w", err)
  91. }
  92. // 格式化查询结果
  93. formattedResult := c.formatNetworksResult(networksResponse, limit, offset, search, vpcId)
  94. // 将结果序列化为JSON格式
  95. resultJSON, err := json.MarshalIndent(formattedResult, "", " ")
  96. if err != nil {
  97. log.Errorf("Fail to serialize result: %s", err)
  98. return nil, fmt.Errorf("fail to serialize result: %w", err)
  99. }
  100. // 返回格式化后的结果
  101. return mcp.NewToolResultText(string(resultJSON)), nil
  102. }
  103. // GetName 返回工具的名称标识符
  104. // 返回值: 工具名称字符串,用于唯一标识该工具
  105. func (c *CloudpodsNetworksTool) GetName() string {
  106. return "cloudpods_list_networks"
  107. }
  108. // formatNetworksResult 格式化网络列表查询结果
  109. // response: 从适配器获取的原始网络数据
  110. // limit: 查询限制数量
  111. // offset: 查询偏移量
  112. // search: 搜索关键词
  113. // vpcId: VPC ID过滤条件
  114. // 返回值: 格式化后的网络列表数据,包含查询信息、网络列表和摘要信息
  115. func (c *CloudpodsNetworksTool) formatNetworksResult(response *models.NetworkListResponse, limit, offset int, search, vpcId string) map[string]interface{} {
  116. // 初始化结果结构,包含查询信息和网络列表
  117. formatted := map[string]interface{}{
  118. "query_info": map[string]interface{}{
  119. "limit": limit,
  120. "offset": offset,
  121. "search": search,
  122. "vpc_id": vpcId,
  123. "total": response.Total,
  124. "count": len(response.Networks),
  125. },
  126. "networks": make([]map[string]interface{}, 0, len(response.Networks)),
  127. }
  128. // 遍历原始网络数据,构造每个网络的详细信息
  129. for _, network := range response.Networks {
  130. // 构造单个网络信息
  131. networkInfo := map[string]interface{}{
  132. "id": network.Id,
  133. "name": network.Name,
  134. "description": network.Description,
  135. "status": network.Status,
  136. "guest_ip_start": network.GuestIpStart,
  137. "guest_ip_end": network.GuestIpEnd,
  138. "guest_ip_mask": network.GuestIpMask,
  139. "guest_gateway": network.GuestGateway,
  140. "guest_dns": network.GuestDns,
  141. "guest_dhcp": network.GuestDhcp,
  142. "guest_ntp": network.GuestNtp,
  143. "guest_domain": network.GuestDomain,
  144. "guest_ip6_start": network.GuestIp6Start,
  145. "guest_ip6_end": network.GuestIp6End,
  146. "guest_ip6_mask": network.GuestIp6Mask,
  147. "guest_gateway6": network.GuestGateway6,
  148. "guest_dns6": network.GuestDns6,
  149. "guest_domain6": network.GuestDomain6,
  150. "vpc": network.Vpc,
  151. "vpc_id": network.VpcId,
  152. "vpc_ext_id": network.VpcExtId,
  153. "wire": network.Wire,
  154. "wire_id": network.WireId,
  155. "zone": network.Zone,
  156. "zone_id": network.ZoneId,
  157. "cloudregion": network.Cloudregion,
  158. "cloudregion_id": network.CloudregionId,
  159. "region": network.Region,
  160. "region_id": network.RegionId,
  161. "provider": network.Provider,
  162. "brand": network.Brand,
  163. "cloud_env": network.CloudEnv,
  164. "environment": network.Environment,
  165. "external_id": network.ExternalId,
  166. "account": network.Account,
  167. "account_id": network.AccountId,
  168. "account_status": network.AccountStatus,
  169. "account_health_status": network.AccountHealthStatus,
  170. "manager": network.Manager,
  171. "manager_id": network.ManagerId,
  172. "manager_domain": network.ManagerDomain,
  173. "manager_domain_id": network.ManagerDomainId,
  174. "manager_project": network.ManagerProject,
  175. "manager_project_id": network.ManagerProjectId,
  176. "server_type": network.ServerType,
  177. "alloc_policy": network.AllocPolicy,
  178. "vlan_id": network.VlanId,
  179. "bgp_type": network.BgpType,
  180. "is_auto_alloc": network.IsAutoAlloc,
  181. "is_classic": network.IsClassic,
  182. "is_default_vpc": network.IsDefaultVpc,
  183. "is_public": network.IsPublic,
  184. "is_system": network.IsSystem,
  185. "is_emulated": network.IsEmulated,
  186. "exit": network.Exit,
  187. "freezed": network.Freezed,
  188. "pending_deleted": network.PendingDeleted,
  189. "pending_deleted_at": network.PendingDeletedAt,
  190. "ports": network.Ports,
  191. "ports_used": network.PortsUsed,
  192. "ports6_used": network.Ports6Used,
  193. "total": network.Total,
  194. "total6": network.Total6,
  195. "vnics": network.Vnics,
  196. "vnics4": network.Vnics4,
  197. "vnics6": network.Vnics6,
  198. "bm_vnics": network.BmVnics,
  199. "bm_reused_vnics": network.BmReusedVnics,
  200. "eip_vnics": network.EipVnics,
  201. "group_vnics": network.GroupVnics,
  202. "lb_vnics": network.LbVnics,
  203. "nat_vnics": network.NatVnics,
  204. "networkinterface_vnics": network.NetworkinterfaceVnics,
  205. "rds_vnics": network.RdsVnics,
  206. "reserve_vnics4": network.ReserveVnics4,
  207. "reserve_vnics6": network.ReserveVnics6,
  208. "routes": network.Routes,
  209. "schedtags": network.Schedtags,
  210. "additional_wires": network.AdditionalWires,
  211. "shared_domains": network.SharedDomains,
  212. "shared_projects": network.SharedProjects,
  213. "project": network.Project,
  214. "project_id": network.ProjectId,
  215. "project_domain": network.ProjectDomain,
  216. "project_metadata": network.ProjectMetadata,
  217. "project_src": network.ProjectSrc,
  218. "tenant": network.Tenant,
  219. "tenant_id": network.TenantId,
  220. "domain_id": network.DomainId,
  221. "public_scope": network.PublicScope,
  222. "public_src": network.PublicSrc,
  223. "source": network.Source,
  224. "progress": network.Progress,
  225. "can_delete": network.CanDelete,
  226. "can_update": network.CanUpdate,
  227. "metadata": network.Metadata,
  228. "created_at": network.CreatedAt,
  229. "updated_at": network.UpdatedAt,
  230. "imported_at": network.ImportedAt,
  231. }
  232. // 将网络信息添加到结果数组中
  233. formatted["networks"] = append(formatted["networks"].([]map[string]interface{}), networkInfo)
  234. }
  235. // 构造摘要信息
  236. formatted["summary"] = map[string]interface{}{
  237. "total_networks": response.Total,
  238. "returned_count": len(response.Networks),
  239. "has_more": response.Total > int64(offset+len(response.Networks)),
  240. "next_offset": offset + len(response.Networks),
  241. }
  242. // 返回格式化后的结果
  243. return formatted
  244. }