diff --git a/METRICS.md b/METRICS.md index cd6a163..3389db7 100644 --- a/METRICS.md +++ b/METRICS.md @@ -54,6 +54,24 @@ - used (int) in bytes - status (string) - status_code (int) 0-active, 1-activating, 2-maintenance, 3-unknown, 4-detaching, 5-unattached, 6-mixed, 7-locked +- ovirtstat_vm + - tags: + - clustername + - dcname + - hostname + - name + - id + - ovirt-engine + - type + - fields: + - cpu_cores (int) + - cpu_sockets (int) + - cpu_threads (int) + - memory_size (int) in bytes + - run_once (bool) + - stateless (bool) + - status (string) + - status_code (int) 0-up, 1-paused, 2..8-misc, 10-unknown, 11-unassigned, 12-notresponding, 13-down - internal_ovirtstat - tags: - ovirt-engine diff --git a/README.md b/README.md index 4632bee..a2b26da 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ ovirtstat_datacenter,name=mydc,id=c3a7efc0-8417-4d1b-bc74-fa6f20d6bf1f,ovirt-eng ovirtstat_host,clustername=mycluster,dcname=mydc,id=b3d53f5d-7ec3-43a8-a52a-15fe7dde25c2,name=myhyp01,ovirt-engine=myovirt,type=rhel cpu_threads=2i,memory_size=1622535045120i,status="up",status_code=0i,cpu_cores=16i,cpu_sockets=2i,cpu_speed=800,reinstallation_required=false,vm_active=5i,vm_migrating=0i,vm_total=5i 1677832224000000000 ovirtstat_storagedomain,id=072cba31-08f3-4a40-9f24-a5ca22ed1d74,name=ovirt-image-repository,ovirt-engine=myovirt,type=image available=0i,connections=0,commited=0i,external_status="ok",external_status_code=0,master=false,status="unattached",status_code=5i,used=0i 1677832224000000000 ovirtstat_storagedomain,id=ec413fb2-c6ce-4bea-a790-2533b728ac93,name=mysd01,ovirt-engine=myovirt,type=data available=3233036632064i,connections=7,commited=16603269824512i,external_status="ok",external_status_code=0,master=true,status="",status_code=3i,used=7761005903872i 1677832224000000000 +virtstat_vm,clustername=mycluster,dcname=mydc,hostname=myhyp01,id=125555e7-fa2c-4d95-a5c4-51f1b9a7f563,name=myvm01,ovirt-engine=myovirt,type=server cpu_cores=1i,cpu_threads=2i,run_once=false,status="up",cpu_sockets=2i,memory_size=40802189312i,stateless=false,status_code=0i 1677832224000000000 internal_ovirtstat,ovirt-engine=myovirt sessions_created=1i,gather_time_ns=803780400i 1677832224000000000 ``` diff --git a/internal/ovirtcollector/cache.go b/internal/ovirtcollector/cache.go index a4bf14e..f8696cb 100644 --- a/internal/ovirtcollector/cache.go +++ b/internal/ovirtcollector/cache.go @@ -121,7 +121,17 @@ func (c *OVirtCollector) getAllDatacentersVMs(ctx context.Context) error { return err } - // TODO + // Get all VMs + vmsService := c.conn.SystemService().VmsService() + vmsResponse, err := vmsService.List().Send() + if err != nil { + return err + } + vms, ok := vmsResponse.Vms() + if !ok { + return fmt.Errorf("Could not get VM list or it is empty") + } + c.vms = vms c.lastVmUpdate = time.Now() return nil @@ -206,3 +216,22 @@ func (c *OVirtCollector) clusterDatacenterName(cl *ovirtsdk.Cluster) string { } return name } + +// hostName returns a host's name from cache +func (c *OVirtCollector) hostName(ho *ovirtsdk.Host) string { + var hoid, id, name string + var ok bool + + if id, ok = ho.Id(); !ok { + return name + } + for _, h := range c.hosts.Slice() { + if hoid, ok = h.Id(); ok { + if hoid == id { + name, _ = h.Name() + break + } + } + } + return name +} diff --git a/internal/ovirtcollector/host.go b/internal/ovirtcollector/host.go index 8755a5b..281bfdf 100644 --- a/internal/ovirtcollector/host.go +++ b/internal/ovirtcollector/host.go @@ -74,7 +74,7 @@ func (c *OVirtCollector) CollectHostInfo( acc.AddError(fmt.Errorf("Cloud not get status for host %s", name)) continue } - cores, sockets, speed = 0, 0, 0 + cores, sockets, speed, threads = 0, 0, 0, 0 if cpu, ok = host.Cpu(); ok { if cort, ok = cpu.Topology(); ok { cores, _ = cort.Cores() diff --git a/internal/ovirtcollector/vms.go b/internal/ovirtcollector/vms.go index 2ade788..502d7c1 100644 --- a/internal/ovirtcollector/vms.go +++ b/internal/ovirtcollector/vms.go @@ -8,9 +8,10 @@ package ovirtcollector import ( "context" "fmt" + "time" "github.com/influxdata/telegraf" - //ovirtsdk "github.com/ovirt/go-ovirt" + ovirtsdk "github.com/ovirt/go-ovirt" ) // CollectVmsInfo gathers oVirt VMs info @@ -18,7 +19,24 @@ func (c *OVirtCollector) CollectVmsInfo( ctx context.Context, acc telegraf.Accumulator, ) error { - var err error + var ( + status ovirtsdk.VmStatus + vtype ovirtsdk.VmType + cl *ovirtsdk.Cluster + ho *ovirtsdk.Host + cpu *ovirtsdk.Cpu + cort *ovirtsdk.CpuTopology + vmtags = make(map[string]string) + vmfields = make(map[string]interface{}) + id, name, dcname string + clname, hostname string + t time.Time + mem, cores int64 + sockets, threads int64 + ok, stateless bool + runOnce bool + err error + ) if c.conn == nil { return fmt.Errorf("Could not get VMs info: %w", ErrorNoClient) @@ -27,8 +45,110 @@ func (c *OVirtCollector) CollectVmsInfo( if err = c.getAllDatacentersVMs(ctx); err != nil { return fmt.Errorf("Could not get all VM entity lists: %w", err) } + t = time.Now() - // TODO + for _, vm := range c.vms.Slice() { + if id, ok = vm.Id(); !ok { + acc.AddError(fmt.Errorf("Found a VM without Id, skipping")) + continue + } + if name, ok = vm.Name(); !ok { + acc.AddError(fmt.Errorf("Found a VM without Name, skipping")) + continue + } + if !c.filterVms.Match(name) { + continue + } + if ho, ok = vm.Host(); ok { + hostname = c.hostName(ho) + if !c.filterHosts.Match(hostname) { + continue + } + } + vtype, _ = vm.Type() + clname, dcname = "", "" + if cl, ok = vm.Cluster(); ok { + clname = c.clusterName(cl) + if !c.filterClusters.Match(clname) { + continue + } + dcname = c.clusterDatacenterName(cl) + } + if status, ok = vm.Status(); !ok { + acc.AddError(fmt.Errorf("Cloud not get status for VM %s", name)) + continue + } + cores, sockets, threads = 0, 0, 0 + if cpu, ok = vm.Cpu(); ok { + if cort, ok = cpu.Topology(); ok { + cores, _ = cort.Cores() + sockets, _ = cort.Sockets() + threads, _ = cort.Threads() + } + } + if mem, ok = vm.Memory(); !ok { + mem = 0 + } + stateless, _ = vm.Stateless() + runOnce, _ = vm.RunOnce() - return nil + vmtags["clustername"] = clname + vmtags["dcname"] = dcname + vmtags["hostname"] = hostname + vmtags["id"] = id + vmtags["name"] = name + vmtags["ovirt-engine"] = c.url.Host + vmtags["type"] = string(vtype) + + vmfields["cpu_cores"] = cores + vmfields["cpu_sockets"] = sockets + vmfields["cpu_threads"] = threads + vmfields["memory_size"] = mem + vmfields["run_once"] = runOnce + vmfields["stateless"] = stateless + vmfields["status"] = string(status) + vmfields["status_code"] = vmStatusCode(status) + + acc.AddFields("ovirtstat_vm", vmfields, vmtags, t) + } + + return err +} + +// vmStatusCode converts VmStatus to int16 for easy alerting +func vmStatusCode(status ovirtsdk.VmStatus) int16 { + switch status { + case ovirtsdk.VMSTATUS_UP: + return 0 + case ovirtsdk.VMSTATUS_PAUSED: + return 1 + case ovirtsdk.VMSTATUS_SUSPENDED: + return 2 + case ovirtsdk.VMSTATUS_POWERING_UP: + return 3 + case ovirtsdk.VMSTATUS_WAIT_FOR_LAUNCH: + return 4 + case ovirtsdk.VMSTATUS_SAVING_STATE: + return 5 + case ovirtsdk.VMSTATUS_MIGRATING: + return 6 + case ovirtsdk.VMSTATUS_POWERING_DOWN: + return 7 + case ovirtsdk.VMSTATUS_RESTORING_STATE: + return 9 + case ovirtsdk.VMSTATUS_REBOOT_IN_PROGRESS: + return 8 + case ovirtsdk.VMSTATUS_UNKNOWN: + return 10 + case ovirtsdk.VMSTATUS_IMAGE_LOCKED: + return 11 + case ovirtsdk.VMSTATUS_UNASSIGNED: + return 12 + case ovirtsdk.VMSTATUS_NOT_RESPONDING: + return 13 + case ovirtsdk.VMSTATUS_DOWN: + return 14 + default: + return 10 + } }