基于govmomi库的VM按资源池过滤及跨DC查询技术问询
解决govmomi中资源池名称显示、按名称过滤VM及跨所有DC搜索的问题
针对你提出的两个核心问题,以及当前输出资源池标识符而非实际名称的痛点,我整理了具体的解决方案和优化后的代码:
1. 按资源池名称过滤VM的简洁实现
govc的逻辑是先定位资源池再过滤VM,govmomi里可以复刻这个思路,而且更高效:
- 先用
Finder.ResourcePoolList搜索匹配目标名称的资源池(支持通配符) - 直接获取这些资源池下关联的VM,避免遍历所有VM后再过滤,节省性能
2. 无需指定DC名称,自动搜索所有数据中心
可以通过Finder.DatacenterList传入*通配符,一次性获取当前vSphere环境下的所有数据中心,完全不用硬编码DC名称,适配不同vSphere实例的差异。
额外修复:显示资源池实际名称
原代码只获取了VM关联的资源池引用,需要通过属性收集器批量查询这些引用对应的资源池名称,建立「引用ID-名称」的映射表,就能替换掉输出里的标识符。
修改后的完整代码
package main import ( "flag" "fmt" "net/url" "os" "sync" "github.com/vmware/govmomi" "github.com/vmware/govmomi/find" "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" "golang.org/x/net/context" ) var vsphereUrl = "https://name:pass@vsphere/sdk" var insecureFlag = false var targetPoolName = "YourTargetPoolName" // 替换为你的目标资源池名称 func exit(err error) { fmt.Fprintf(os.Stderr, "Error: %s\n", err) os.Exit(1) } // 批量获取资源池引用对应的名称,建立映射表 func getResourcePoolNameMap(ctx context.Context, pc *property.Collector, poolRefs []types.ManagedObjectReference) map[string]string { nameMap := make(map[string]string) if len(poolRefs) == 0 { return nameMap } var pools []mo.ResourcePool err := pc.Retrieve(ctx, poolRefs, []string{"name"}, &pools) if err != nil { exit(err) } for _, pool := range pools { nameMap[pool.Reference().Value] = pool.Name } return nameMap } func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() flag.Parse() u, err := url.Parse(vsphereUrl) if err != nil { exit(err) } c, err := govmomi.NewClient(ctx, u, insecureFlag) if err != nil { exit(err) } f := find.NewFinder(c.Client, true) // 获取当前vSphere下的所有DC,无需硬编码名称 dcs, err := f.DatacenterList(ctx, "*") if err != nil { exit(err) } var group sync.WaitGroup for _, dc := range dcs { group.Add(1) // 启动goroutine处理每个DC的查询 go func(ctx context.Context, dc mo.Datacenter, f *find.Finder, c *govmomi.Client, group *sync.WaitGroup, targetPool string) { defer group.Done() f.SetDatacenter(&dc) // 查找当前DC下匹配目标名称的资源池 targetPools, err := f.ResourcePoolList(ctx, targetPool) if err != nil { fmt.Fprintf(os.Stderr, "DC %s: 查找资源池%s失败: %s\n", dc.Name, targetPool, err) return } if len(targetPools) == 0 { fmt.Printf("DC %s: 未找到名称为%s的资源池\n", dc.Name, targetPool) return } pc := property.DefaultCollector(c.Client) var allVMs []mo.VirtualMachine // 遍历每个目标资源池,获取池内的VM for _, pool := range targetPools { var poolObj mo.ResourcePool err := pc.RetrieveOne(ctx, pool.Reference(), []string{"vm"}, &poolObj) if err != nil { fmt.Fprintf(os.Stderr, "DC %s: 获取资源池%s下的VM失败: %s\n", dc.Name, pool.Name, err) continue } if len(poolObj.Vm) == 0 { continue } // 获取这些VM的名称和关联资源池信息 var vms []mo.VirtualMachine err = pc.Retrieve(ctx, poolObj.Vm, []string{"name", "resourcePool"}, &vms) if err != nil { fmt.Fprintf(os.Stderr, "DC %s: 获取VM信息失败: %s\n", dc.Name, err) continue } allVMs = append(allVMs, vms...) } // 建立资源池ID到名称的映射 poolRefs := make([]types.ManagedObjectReference, 0, len(allVMs)) for _, vm := range allVMs { poolRefs = append(poolRefs, vm.ResourcePool) } poolNameMap := getResourcePoolNameMap(ctx, pc, poolRefs) // 输出格式化结果 fmt.Printf("\n=== DC: %s ===\n", dc.Name) for _, vm := range allVMs { poolName := poolNameMap[vm.ResourcePool.Value] fmt.Printf("VM名称: %s | 资源池: %s\n", vm.Name, poolName) } }(ctx, dc, f, c, &group, targetPoolName) } group.Wait() fmt.Println("\n所有查询完成。") }
关键优化点说明
- 自动遍历所有DC:通过
f.DatacenterList(ctx, "*")动态获取所有数据中心,适配不同vSphere环境的DC名称差异 - 精准过滤VM:先定位目标资源池,再直接获取池内VM,比全局遍历VM后过滤效率更高
- 资源池名称显示:通过批量查询资源池属性建立映射表,彻底替换输出中的标识符
- 健壮的错误处理:单个DC的查询失败不会导致整个程序退出,同时输出明确的错误提示
内容的提问来源于stack exchange,提问作者Alex Nikitin
相关产品推荐
相关产品推荐

