Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/scollector+bosun: get vsphere mounted datastores and expose via h… #1515

Merged
merged 1 commit into from
Dec 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions cmd/bosun/sched/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,24 @@ func (s *Schedule) Host(filter string) (map[string]*HostData, error) {
if iface != nil {
iface.Description = val
}
case "dataStores":
dataStores := []string{}
err = json.Unmarshal([]byte(val), &dataStores)
if err != nil {
slog.Errorf("error unmarshalling datastores for host %s while generating host api: %s", host.Name, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue or return here. Don't keep going.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@captncraig Since the host API generates a lot of information, I don't want single errors preventing the rest of the information from being returned

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, then we chould continue the metadata loop. Should not iterate over dataStores if we just failed to deserialize it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@captncraig My assumption was that in we fail to deserialize it, the array will be empty, so the range is a no-op.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible it has a few partial objects already created there. I'd rather skip it to be safe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@captncraig The code makes it sounds like it checks for this first, see https://golang.org/src/encoding/json/decode.go?s=2621:2669#L64

"""
// Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
"""

}
for _, dataStore := range dataStores {
tags := opentsdb.TagSet{"name": dataStore}.String()
total, totalTs, totalErr := s.Search.GetLast("vsphere.disk.space_total", tags, false)
used, usedTs, usedErr := s.Search.GetLast("vsphere.disk.space_used", tags, false)
if totalErr != nil || usedErr != nil || totalTs < 1 || usedTs < 1 {
continue
}
host.Disks[dataStore] = &Disk{
TotalBytes: total,
UsedBytes: used,
}
}
case "mac":
if iface != nil {
iface.MAC = val
Expand Down
53 changes: 49 additions & 4 deletions cmd/scollector/collectors/vsphere.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package collectors

import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io"
Expand Down Expand Up @@ -36,10 +37,12 @@ func c_vsphere(user, pwd, host string, cpuIntegrators map[string]tsIntegrator) (
return nil, err
}
var md opentsdb.MultiDataPoint
if err := vsphereHost(v, &md, cpuIntegrators); err != nil {
// reference ID to cleaned name
hostKey := make(map[string]string)
if err := vsphereHost(v, &md, cpuIntegrators, hostKey); err != nil {
return nil, err
}
if err := vsphereDatastore(v, &md); err != nil {
if err := vsphereDatastore(v, &md, hostKey); err != nil {
return nil, err
}
if err := vsphereGuest(util.Clean(host), v, &md); err != nil {
Expand All @@ -48,15 +51,28 @@ func c_vsphere(user, pwd, host string, cpuIntegrators map[string]tsIntegrator) (
return md, nil
}

func vsphereDatastore(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint) error {
type DatastoreHostMount struct {
Key string `xml:"key"`
MountInfo struct {
Accessible bool `xml:"accessible"`
AccessMode string `xml:"accessMode"`
Mounted bool `xml:"mounted"`
Path string `xml:"path"`
} `xml:"mountInfo"`
}

func vsphereDatastore(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint, hostKey map[string]string) error {
res, err := v.Info("Datastore", []string{
"name",
"host",
"summary.capacity",
"summary.freeSpace",
})
if err != nil {
return err
}
// host to mounted data stores
hostStores := make(map[string][]string)
var Error error
for _, r := range res {
var name string
Expand Down Expand Up @@ -92,6 +108,27 @@ func vsphereDatastore(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint) error {
Add(md, "vsphere.disk.space_free", i, tags, metadata.Gauge, metadata.Bytes, "")
diskFree = i
}
case "ArrayOfDatastoreHostMount":
switch p.Name {
case "host":
d := xml.NewDecoder(bytes.NewBufferString(p.Val.Inner))

for {
var m DatastoreHostMount
err := d.Decode(&m)
if err == io.EOF {
break
}
if err != nil {
return err
}
if host, ok := hostKey[m.Key]; ok {
if m.MountInfo.Mounted && m.MountInfo.Accessible {
hostStores[host] = append(hostStores[host], name)
}
}
}
}
}
}
if diskTotal > 0 && diskFree > 0 {
Expand All @@ -101,6 +138,13 @@ func vsphereDatastore(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint) error {
Add(md, osDiskPctFree, float64(diskFree)/float64(diskTotal)*100, tags, metadata.Gauge, metadata.Pct, "")
}
}
for host, stores := range hostStores {
j, err := json.Marshal(stores)
if err != nil {
slog.Errorf("error marshaling datastores for host %v: %v", host, err)
}
metadata.AddMeta("", opentsdb.TagSet{"host": host}, "dataStores", string(j), false)
}
return Error
}

Expand All @@ -113,7 +157,7 @@ type HostSystemIdentificationInfo struct {
} `xml:"identifierType"`
}

func vsphereHost(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint, cpuIntegrators map[string]tsIntegrator) error {
func vsphereHost(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint, cpuIntegrators map[string]tsIntegrator, hostKey map[string]string) error {
res, err := v.Info("HostSystem", []string{
"name",
"summary.hardware.cpuMhz",
Expand Down Expand Up @@ -142,6 +186,7 @@ func vsphereHost(v *vsphere.Vsphere, md *opentsdb.MultiDataPoint, cpuIntegrators
Error = fmt.Errorf("vsphere: empty name")
continue
}
hostKey[r.ID] = name
tags := opentsdb.TagSet{
"host": name,
}
Expand Down