From 934d7aecfcb096db98674dc85bde605e83fe5400 Mon Sep 17 00:00:00 2001 From: Henrik Hodne Date: Fri, 26 Aug 2016 21:30:39 +0200 Subject: [PATCH] Fetch the list of known hosts and base VMs on boot (#10) This lets us see hosts that never power on/power off VMs and base images that don't get cloned instantly. Fixes #1 --- CHANGELOG.md | 2 + cmd/collectd-vsphere/main.go | 5 +++ vsphere_event_listener.go | 79 +++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eb0dee..5ddec5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ IMPROVEMENTS: * Add log messages + * Fetch the list of hosts and base VMs on boot to include them in the metrics + immediately (#1) ## v1.0.0 (August 26, 2016) diff --git a/cmd/collectd-vsphere/main.go b/cmd/collectd-vsphere/main.go index 8e173e9..82a3360 100644 --- a/cmd/collectd-vsphere/main.go +++ b/cmd/collectd-vsphere/main.go @@ -76,6 +76,11 @@ func main() { Usage: "path to the vSphere cluster to monitor events on", EnvVars: []string{"VSPHERE_CLUSTER"}, }, + &cli.StringFlag{ + Name: "vsphere-base-vm-folder", + Usage: "path to the vSphere folder containing base VMs", + EnvVars: []string{"VSPHERE_BASE_VM_FOLDER"}, + }, &cli.StringFlag{ Name: "sentry-dsn", Usage: "DSN for Sentry integration", diff --git a/vsphere_event_listener.go b/vsphere_event_listener.go index 8e0cb70..eaf4684 100644 --- a/vsphere_event_listener.go +++ b/vsphere_event_listener.go @@ -7,6 +7,8 @@ import ( "github.com/vmware/govmomi" "github.com/vmware/govmomi/event" "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" "golang.org/x/net/context" ) @@ -24,6 +26,7 @@ type VSphereConfig struct { URL *url.URL Insecure bool ClusterPath string + BaseVMPath string } // NewVSphereEventListener creates a VSphereEventListener with a given @@ -39,7 +42,18 @@ func NewVSphereEventListener(config VSphereConfig, statsCollector *StatsCollecto // Start starts the event listener and begins reporting stats to the // StatsCollector. func (l *VSphereEventListener) Start() error { - l.makeClient() + err := l.makeClient() + if err != nil { + return errors.Wrap(err, "couldn't create vSphere client") + } + err = l.prefillHosts() + if err != nil { + return errors.Wrap(err, "couldn't prefill hosts") + } + err = l.prefillBaseVMs() + if err != nil { + return errors.Wrap(err, "couldn't prefill base VMs") + } clusterRef, err := l.clusterReference() if err != nil { @@ -88,3 +102,66 @@ func (l *VSphereEventListener) clusterReference() (types.ManagedObjectReference, return cluster.Reference(), nil } + +func (l *VSphereEventListener) prefillHosts() error { + clusterRef, err := l.clusterReference() + if err != nil { + return errors.Wrap(err, "failed to get reference to compute cluster") + } + + hosts, err := object.NewClusterComputeResource(l.client.Client, clusterRef).Hosts(context.TODO()) + if err != nil { + return errors.Wrap(err, "failed to list hosts in compute cluster") + } + + for _, host := range hosts { + var mhost mo.HostSystem + err := host.Properties(context.TODO(), host.Reference(), []string{"summary"}, &mhost) + if err != nil { + return errors.Wrap(err, "failed to get summary for host") + } + name := mhost.Summary.Config.Name + if name != "" { + l.statsCollector.ensureHostExists(name) + } + } + + return nil +} + +func (l *VSphereEventListener) prefillBaseVMs() error { + if l.config.BaseVMPath == "" { + // Skip if no base VM path, for backwards compatibility with v1.0.0 + return nil + } + + finder := find.NewFinder(l.client.Client, true) + folder, err := finder.Folder(context.TODO(), l.config.BaseVMPath) + if err != nil { + return errors.Wrap(err, "failed to find base vm folder") + } + + children, err := folder.Children(context.TODO()) + if err != nil { + return errors.Wrap(err, "failed to list children of base vm folder") + } + + for _, vmRef := range children { + vm, ok := vmRef.(*object.VirtualMachine) + if !ok { + continue + } + + var mvm mo.VirtualMachine + err := vm.Properties(context.TODO(), vm.Reference(), []string{"config"}, &mvm) + if err != nil { + return errors.Wrap(err, "failed to get config for base VM") + } + name := mvm.Config.Name + if name != "" { + l.statsCollector.ensureBaseVMExists(name) + } + } + + return nil +}