This commit is contained in:
@@ -56,7 +56,7 @@ func main() {
|
|||||||
log.Printf("Got authentication cookie: %s\n", ucsClient.Cookie)
|
log.Printf("Got authentication cookie: %s\n", ucsClient.Cookie)
|
||||||
|
|
||||||
// Register prometheus exporters
|
// Register prometheus exporters
|
||||||
exporter := exporters.NewUcsmTemperatureCollector(ucsClient, ctx)
|
exporter := exporters.NewUcsmExporters(ucsClient, ctx)
|
||||||
prometheus.MustRegister(exporter)
|
prometheus.MustRegister(exporter)
|
||||||
|
|
||||||
// Start prometheus exporter
|
// Start prometheus exporter
|
||||||
@@ -64,4 +64,6 @@ func main() {
|
|||||||
|
|
||||||
// TODO - run this in a go routine to avoid blocking, as per cbs code
|
// TODO - run this in a go routine to avoid blocking, as per cbs code
|
||||||
log.Fatal(http.ListenAndServe(*listenPort, nil))
|
log.Fatal(http.ListenAndServe(*listenPort, nil))
|
||||||
|
|
||||||
|
// TODO - log off from UCS manager
|
||||||
}
|
}
|
||||||
|
3
go.mod
3
go.mod
@@ -5,6 +5,7 @@ go 1.21.0
|
|||||||
require (
|
require (
|
||||||
github.com/dnaeon/go-ucs v0.0.0-20180427075322-a04ea35bf5de
|
github.com/dnaeon/go-ucs v0.0.0-20180427075322-a04ea35bf5de
|
||||||
github.com/prometheus/client_golang v1.16.0
|
github.com/prometheus/client_golang v1.16.0
|
||||||
|
golang.org/x/sync v0.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -20,4 +21,4 @@ require (
|
|||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/dnaeon/go-ucs => ./local/go-ucs
|
replace github.com/dnaeon/go-ucs => ./local/go-ucs
|
||||||
|
4
go.sum
4
go.sum
@@ -4,8 +4,6 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
|
|||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dnaeon/go-ucs v0.0.0-20180427075322-a04ea35bf5de h1:TPQ2PEbeZy0m8Y/zO+IQx9pUDMqfanACLJqREaLroJU=
|
|
||||||
github.com/dnaeon/go-ucs v0.0.0-20180427075322-a04ea35bf5de/go.mod h1:CnATpmPv6+QWYn/4O/qrRmxhSvfsiTMB4mVBfsWwKs8=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@@ -25,6 +23,8 @@ github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr
|
|||||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||||
|
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
@@ -1,77 +0,0 @@
|
|||||||
package exporters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/xml"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/dnaeon/go-ucs/api"
|
|
||||||
"github.com/dnaeon/go-ucs/mo"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UcsmBladeCollector struct {
|
|
||||||
ucsClient *api.Client
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
type ComputeMbTempStats struct {
|
|
||||||
XMLName xml.Name `xml:"computeMbTempStats"`
|
|
||||||
Dn string `xml:"dn,attr,omitempty"`
|
|
||||||
FmTempSenIo string `xml:"fmTempSenIo,attr,omitempty"`
|
|
||||||
FmTempSenRear string `xml:"fmTempSenRear,attr,omitempty"`
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func NewUcsmBladeCollector(client *api.Client, ctx context.Context) *UcsmTemperaturesCollector {
|
|
||||||
return &UcsmTemperaturesCollector{
|
|
||||||
ucsClient: client,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Describe prometheus describe
|
|
||||||
func (u *UcsmBladeCollector) Describe(ch chan<- *prometheus.Desc) {
|
|
||||||
log.Printf("Running Describe for UcsmTemperaturesCollector\n")
|
|
||||||
ch <- prometheus.NewDesc("ucsm_temperature_sensor",
|
|
||||||
"UCSM temperature sensor for motherboard/cpu/psu",
|
|
||||||
[]string{"server", "component", "description"}, nil,
|
|
||||||
)
|
|
||||||
ch <- prometheus.NewDesc("ucsm_temperature_sensor",
|
|
||||||
"UCSM temperature sensor for motherboard/cpu/psu",
|
|
||||||
[]string{"server", "component", "description"}, nil,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect prometheus collect
|
|
||||||
func (u *UcsmBladeCollector) Collect(ch chan<- prometheus.Metric) {
|
|
||||||
// The type into which we unmarshal the result data
|
|
||||||
type blades struct {
|
|
||||||
XMLName xml.Name
|
|
||||||
Blades []mo.ComputeBlade `xml:"computeBlade"`
|
|
||||||
}
|
|
||||||
|
|
||||||
bladeRequest := api.ConfigResolveClassRequest{
|
|
||||||
Cookie: u.ucsClient.Cookie,
|
|
||||||
ClassId: "computeBlade",
|
|
||||||
InHierarchical: "false",
|
|
||||||
}
|
|
||||||
|
|
||||||
var bladeList blades
|
|
||||||
|
|
||||||
log.Println("Retrieving managed objects with class `computeBlade`")
|
|
||||||
|
|
||||||
if err := u.ucsClient.ConfigResolveClass(u.ctx, bladeRequest, &bladeList); err != nil {
|
|
||||||
log.Fatalf("Unable to retrieve `computeBlade` managed object: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Retrieved %d compute blades\n", len(bladeList.Blades))
|
|
||||||
for _, blade := range bladeList.Blades {
|
|
||||||
log.Printf("%s:\n", blade.Dn)
|
|
||||||
log.Printf("\tNumber of CPUs: %d\n", blade.NumOfCpus)
|
|
||||||
log.Printf("\tTotal Memory: %d\n", blade.TotalMemory)
|
|
||||||
log.Printf("\tModel: %s\n", blade.Model)
|
|
||||||
log.Printf("\tVendor: %s\n", blade.Vendor)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
123
internal/exporters/UcsmPortStats.go
Normal file
123
internal/exporters/UcsmPortStats.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package exporters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/xml"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dnaeon/go-ucs/api"
|
||||||
|
"github.com/dnaeon/go-ucs/mo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Define the fields we will send back to the collector
|
||||||
|
type UcsmVnicPortStats struct {
|
||||||
|
Server string
|
||||||
|
Component string
|
||||||
|
Metrics map[string]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UcsExporters) GetUcsmPortStats(ctx context.Context, ucsmPortStatsChannel chan []UcsmVnicPortStats) {
|
||||||
|
|
||||||
|
portStatsResults := make([]UcsmVnicPortStats, 0)
|
||||||
|
|
||||||
|
// The type into which we unmarshal the result data
|
||||||
|
type vnicStats struct {
|
||||||
|
XMLName xml.Name
|
||||||
|
VnicStats []mo.AdaptorVnicStats `xml:"adaptorVnicStats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the request we are making to UCS Manager
|
||||||
|
vnicStatsRequest := api.ConfigResolveClassRequest{
|
||||||
|
Cookie: u.ucsClient.Cookie,
|
||||||
|
ClassId: "adaptorVnicStats",
|
||||||
|
InHierarchical: "false",
|
||||||
|
}
|
||||||
|
|
||||||
|
var vnicStatsObject vnicStats
|
||||||
|
|
||||||
|
log.Println("Retrieving managed objects with class `adaptorVnicStats`")
|
||||||
|
|
||||||
|
if err := u.ucsClient.ConfigResolveClass(u.ctx, vnicStatsRequest, &vnicStatsObject); err != nil {
|
||||||
|
log.Fatalf("Unable to retrieve `computeMbTempStats` managed object: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Retrieved port stats for %d vnics\n", len(vnicStatsObject.VnicStats))
|
||||||
|
for _, vnic := range vnicStatsObject.VnicStats {
|
||||||
|
var bladeDn string
|
||||||
|
|
||||||
|
// Extract the bladeDn
|
||||||
|
startIndex := strings.Index(vnic.Dn, "/adaptor-")
|
||||||
|
if startIndex != -1 {
|
||||||
|
bladeDn = vnic.Dn[:startIndex]
|
||||||
|
} else {
|
||||||
|
bladeDn = vnic.Dn
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Network stats for blade %s and component %s:\n", bladeDn, vnic.Dn)
|
||||||
|
log.Printf("Bytes Rx: %d, Bytes Tx: %d\n", vnic.BytesRx, vnic.BytesTx)
|
||||||
|
log.Printf("Packets Rx: %d, Packets Tx: %d\n", vnic.PacketsRx, vnic.PacketsTx)
|
||||||
|
log.Printf("Dropped Rx: %d, Dropped Tx: %d\n", vnic.DroppedRx, vnic.DroppedTx)
|
||||||
|
log.Printf("Error Rx: %d, Error Tx: %d\n", vnic.ErrorsRx, vnic.ErrorsTx)
|
||||||
|
|
||||||
|
// Create a map of all the values we care about
|
||||||
|
portMetrics := make(map[string]uint64)
|
||||||
|
portMetrics["ucsm_vnic_rx_total_packets"] = vnic.PacketsRx
|
||||||
|
portMetrics["ucsm_vnic_tx_total_packets"] = vnic.PacketsTx
|
||||||
|
portMetrics["ucsm_vnic_rx_total_bytes"] = vnic.BytesRx
|
||||||
|
portMetrics["ucsm_vnic_tx_total_bytes"] = vnic.BytesTx
|
||||||
|
portMetrics["ucsm_vnic_rx_dropped"] = vnic.DroppedRx
|
||||||
|
portMetrics["ucsm_vnic_tx_dropped"] = vnic.DroppedTx
|
||||||
|
portMetrics["ucsm_vnic_rx_error"] = vnic.ErrorsRx
|
||||||
|
portMetrics["ucsm_vnic_tx_error"] = vnic.ErrorsTx
|
||||||
|
|
||||||
|
// Add the metrics along with the other properties to the results
|
||||||
|
vnicPortStats := UcsmVnicPortStats{
|
||||||
|
Server: bladeDn,
|
||||||
|
Component: vnic.Dn,
|
||||||
|
Metrics: portMetrics,
|
||||||
|
}
|
||||||
|
|
||||||
|
portStatsResults = append(portStatsResults, vnicPortStats)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Substring the Dn for the temperatures to get the Dn for the parent blade itself
|
||||||
|
bladeDn := strings.Replace(temps.Dn, "/board/temp-stats", "", -1)
|
||||||
|
|
||||||
|
log.Printf("Temps for blade %s:\n", bladeDn)
|
||||||
|
log.Printf("Front Temperature: %v\n", temps.FmTempSenIo)
|
||||||
|
log.Printf("Rear Temperature: %v\n", temps.FmTempSenRear)
|
||||||
|
|
||||||
|
boardTempFront := UcsmPortStats{
|
||||||
|
Server: bladeDn,
|
||||||
|
Component: temps.Dn,
|
||||||
|
Description: "motherboard_front_temperature",
|
||||||
|
Value: temps.FmTempSenIo,
|
||||||
|
}
|
||||||
|
|
||||||
|
boardTempRear := UcsmPortStats{
|
||||||
|
Server: bladeDn,
|
||||||
|
Component: temps.Dn,
|
||||||
|
Description: "motherboard_rear_temperature",
|
||||||
|
Value: temps.FmTempSenRear,
|
||||||
|
}
|
||||||
|
|
||||||
|
portStatsResults = append(portStatsResults, boardTempFront)
|
||||||
|
portStatsResults = append(portStatsResults, boardTempRear)
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
// TODO - work out a better way of running this twice, once for each temperature sensor
|
||||||
|
|
||||||
|
metric1 := prometheus.MustNewConstMetric(u.UcsmTemperatures, prometheus.GaugeValue, temps.FmTempSenIo, bladeDn, temps.Dn, "motherboard_rear_temperature")
|
||||||
|
// send the data
|
||||||
|
ch <- metric1
|
||||||
|
|
||||||
|
// generate the metric
|
||||||
|
metric2 := prometheus.MustNewConstMetric(u.UcsmTemperatures, prometheus.GaugeValue, temps.FmTempSenRear, bladeDn, temps.Dn, "motherboard_front_temperature")
|
||||||
|
// send the data
|
||||||
|
ch <- metric2
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
log.Printf("GetUcsmPortStats sending results to channel\n")
|
||||||
|
ucsmPortStatsChannel <- portStatsResults
|
||||||
|
}
|
@@ -8,9 +8,17 @@ import (
|
|||||||
|
|
||||||
"github.com/dnaeon/go-ucs/api"
|
"github.com/dnaeon/go-ucs/api"
|
||||||
"github.com/dnaeon/go-ucs/mo"
|
"github.com/dnaeon/go-ucs/mo"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Define the fields we will send back to the collector
|
||||||
|
type UcsmTemperatures struct {
|
||||||
|
Server string
|
||||||
|
Component string
|
||||||
|
Description string
|
||||||
|
Value float64
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
type UcsmTemperaturesCollector struct {
|
type UcsmTemperaturesCollector struct {
|
||||||
ucsClient *api.Client
|
ucsClient *api.Client
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -18,6 +26,7 @@ type UcsmTemperaturesCollector struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var metrics []prometheus.Desc
|
var metrics []prometheus.Desc
|
||||||
|
*/
|
||||||
|
|
||||||
//var ucsClient *api.Client
|
//var ucsClient *api.Client
|
||||||
//var ctx context.Context
|
//var ctx context.Context
|
||||||
@@ -30,64 +39,44 @@ var metrics []prometheus.Desc
|
|||||||
FmTempSenRear string `xml:"fmTempSenRear,attr,omitempty"`
|
FmTempSenRear string `xml:"fmTempSenRear,attr,omitempty"`
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
func NewUcsmTemperatureCollector(client *api.Client, ctx context.Context) *UcsmTemperaturesCollector {
|
/*
|
||||||
|
func NewUcsmTemperatureCollector(client *api.Client, ctx context.Context) *UcsExporters {
|
||||||
|
|
||||||
/*
|
return &UcsExporters{
|
||||||
ucsClient = client
|
|
||||||
ctx = ctx
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
return &main.Collector{
|
|
||||||
UcsmTemperature: prometheus.NewDesc("ucsm_temperature_sensor",
|
|
||||||
"UCSM temperature sensor for motherboard/cpu/psu",
|
|
||||||
[]string{"server", "component", "description"}, nil,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return &UcsmTemperaturesCollector{
|
|
||||||
ucsClient: client,
|
ucsClient: client,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
metrics: []*prometheus.Desc{
|
UcsmTemperatures: prometheus.NewDesc("ucsm_temperature_sensor",
|
||||||
prometheus.NewDesc(
|
"UCSM temperature sensor for motherboard/cpu/psu",
|
||||||
"ucsm_temperature_sensor",
|
[]string{"server", "component", "description"}, nil,
|
||||||
"UCSM temperature sensor for motherboard/cpu/psu",
|
),
|
||||||
[]string{"server", "component", "description"}, nil,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe prometheus describe
|
// Describe prometheus describe
|
||||||
func (u *UcsmTemperaturesCollector) Describe(ch chan<- *prometheus.Desc) {
|
func (u *UcsExporters) Describe(ch chan<- *prometheus.Desc) {
|
||||||
log.Printf("Running Describe for UcsmTemperaturesCollector\n")
|
log.Printf("Running Describe for UcsmTemperaturesCollector\n")
|
||||||
|
|
||||||
// Describe the metrics and send them on the channel
|
ch <- u.UcsmTemperatures
|
||||||
for _, desc := range u.metrics {
|
|
||||||
ch <- desc
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
metricDesc := prometheus.NewDesc("ucsm_temperature_sensor",
|
|
||||||
"UCSM temperature sensor for motherboard/cpu/psu",
|
|
||||||
[]string{"server", "component", "description"}, nil)
|
|
||||||
|
|
||||||
fmt.Printf("metricDesc: %v\n", *metricDesc)
|
|
||||||
|
|
||||||
metrics = append(metrics, *metricDesc)
|
|
||||||
ch <- metricDesc
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Collect prometheus collect
|
// Collect prometheus collect
|
||||||
func (u *UcsmTemperaturesCollector) Collect(ch chan<- prometheus.Metric) {
|
func (u *UcsExporters) GetUcsmTemperatures(ctx context.Context, ucsmTempsChannel chan []UcsmTemperatures) {
|
||||||
|
/*
|
||||||
|
wg.Add(1)
|
||||||
|
defer wg.Done()
|
||||||
|
defer close(ucsmTempsChannel)
|
||||||
|
*/
|
||||||
|
temperatureResults := make([]UcsmTemperatures, 0)
|
||||||
|
|
||||||
// The type into which we unmarshal the result data
|
// The type into which we unmarshal the result data
|
||||||
type temps struct {
|
type temps struct {
|
||||||
XMLName xml.Name
|
XMLName xml.Name
|
||||||
Temperatures []mo.ComputeMbTempStats `xml:"computeMbTempStats"`
|
Temperatures []mo.ComputeMbTempStats `xml:"computeMbTempStats"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define the request we are making to UCS Manager
|
||||||
tempRequest := api.ConfigResolveClassRequest{
|
tempRequest := api.ConfigResolveClassRequest{
|
||||||
Cookie: u.ucsClient.Cookie,
|
Cookie: u.ucsClient.Cookie,
|
||||||
ClassId: "computeMbTempStats",
|
ClassId: "computeMbTempStats",
|
||||||
@@ -96,6 +85,7 @@ func (u *UcsmTemperaturesCollector) Collect(ch chan<- prometheus.Metric) {
|
|||||||
|
|
||||||
var boardTempList temps
|
var boardTempList temps
|
||||||
|
|
||||||
|
//cswg := new(sync.WaitGroup)
|
||||||
log.Println("Retrieving managed objects with class `computeMbTempStats`")
|
log.Println("Retrieving managed objects with class `computeMbTempStats`")
|
||||||
|
|
||||||
if err := u.ucsClient.ConfigResolveClass(u.ctx, tempRequest, &boardTempList); err != nil {
|
if err := u.ucsClient.ConfigResolveClass(u.ctx, tempRequest, &boardTempList); err != nil {
|
||||||
@@ -111,28 +101,41 @@ func (u *UcsmTemperaturesCollector) Collect(ch chan<- prometheus.Metric) {
|
|||||||
log.Printf("Front Temperature: %v\n", temps.FmTempSenIo)
|
log.Printf("Front Temperature: %v\n", temps.FmTempSenIo)
|
||||||
log.Printf("Rear Temperature: %v\n", temps.FmTempSenRear)
|
log.Printf("Rear Temperature: %v\n", temps.FmTempSenRear)
|
||||||
|
|
||||||
// TODO - work out a better way of running this twice, once for each temperature sensor
|
boardTempFront := UcsmTemperatures{
|
||||||
|
Server: bladeDn,
|
||||||
|
Component: temps.Dn,
|
||||||
|
Description: "motherboard_front_temperature",
|
||||||
|
Value: temps.FmTempSenIo,
|
||||||
|
}
|
||||||
|
|
||||||
// Collect the actual metric values and send them on the channel
|
boardTempRear := UcsmTemperatures{
|
||||||
for _, desc := range u.metrics {
|
Server: bladeDn,
|
||||||
|
Component: temps.Dn,
|
||||||
|
Description: "motherboard_rear_temperature",
|
||||||
|
Value: temps.FmTempSenRear,
|
||||||
|
}
|
||||||
|
|
||||||
// populate the labels array
|
temperatureResults = append(temperatureResults, boardTempFront)
|
||||||
//labelValues := []string{bladeDn, temps.Dn, "motherboard_rear_temperature"}
|
temperatureResults = append(temperatureResults, boardTempRear)
|
||||||
|
|
||||||
// generate the metric
|
/*
|
||||||
metric1 := prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, temps.FmTempSenIo, bladeDn, temps.Dn, "motherboard_rear_temperature")
|
// TODO - work out a better way of running this twice, once for each temperature sensor
|
||||||
|
|
||||||
|
metric1 := prometheus.MustNewConstMetric(u.UcsmTemperatures, prometheus.GaugeValue, temps.FmTempSenIo, bladeDn, temps.Dn, "motherboard_rear_temperature")
|
||||||
// send the data
|
// send the data
|
||||||
ch <- metric1
|
ch <- metric1
|
||||||
|
|
||||||
// generate the metric
|
// generate the metric
|
||||||
metric2 := prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, temps.FmTempSenRear, bladeDn, temps.Dn, "motherboard_front_temperature")
|
metric2 := prometheus.MustNewConstMetric(u.UcsmTemperatures, prometheus.GaugeValue, temps.FmTempSenRear, bladeDn, temps.Dn, "motherboard_front_temperature")
|
||||||
// send the data
|
// send the data
|
||||||
ch <- metric2
|
ch <- metric2
|
||||||
}
|
*/
|
||||||
|
|
||||||
//ch <- prometheus.MustNewConstMetric()
|
|
||||||
}
|
}
|
||||||
|
//cswg.Wait()
|
||||||
|
|
||||||
|
log.Printf("GetUcsmTemperatures sending results to channel\n")
|
||||||
|
ucsmTempsChannel <- temperatureResults
|
||||||
|
//return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
141
internal/exporters/exporters.go
Normal file
141
internal/exporters/exporters.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package exporters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/dnaeon/go-ucs/api"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UcsExporters struct {
|
||||||
|
// Define each type of metric here
|
||||||
|
UcsmTemperatures *prometheus.Desc
|
||||||
|
UcsmVnicStatsRxTotalPkts *prometheus.Desc
|
||||||
|
UcsmVnicStatsTxTotalPkts *prometheus.Desc
|
||||||
|
UcsmVnicStatsRxTotalBytes *prometheus.Desc
|
||||||
|
UcsmVnicStatsTxTotalBytes *prometheus.Desc
|
||||||
|
UcsmVnicStatsRxDropped *prometheus.Desc
|
||||||
|
UcsmVnicStatsTxDropped *prometheus.Desc
|
||||||
|
UcsmVnicStatsRxError *prometheus.Desc
|
||||||
|
UcsmVnicStatsTxError *prometheus.Desc
|
||||||
|
|
||||||
|
// Additional properties required
|
||||||
|
ucsClient *api.Client
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUcsmExporters(client *api.Client, ctx context.Context) *UcsExporters {
|
||||||
|
return &UcsExporters{
|
||||||
|
ucsClient: client,
|
||||||
|
ctx: ctx,
|
||||||
|
// UCS Temperatures
|
||||||
|
UcsmTemperatures: prometheus.NewDesc("ucsm_temperature_sensor",
|
||||||
|
"UCSM temperature sensor for motherboard/cpu/psu",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
// UCS Network statistics
|
||||||
|
UcsmVnicStatsRxTotalPkts: prometheus.NewDesc("ucsm_vnic_rx_total_packets",
|
||||||
|
"UCSM Ethernet RX counter: total_packets",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsTxTotalPkts: prometheus.NewDesc("ucsm_vnic_tx_total_packets",
|
||||||
|
"UCSM Ethernet TX counter: total_packets",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsRxTotalBytes: prometheus.NewDesc("ucsm_vnic_rx_total_bytes",
|
||||||
|
"UCSM Ethernet RX counter: total_bytes",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsTxTotalBytes: prometheus.NewDesc("ucsm_vnic_tx_total_bytes",
|
||||||
|
"UCSM Ethernet TX counter: total_bytes",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsRxDropped: prometheus.NewDesc("ucsm_vnic_rx_dropped",
|
||||||
|
"UCSM Ethernet Rx Dropped counter: total_count",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsTxDropped: prometheus.NewDesc("ucsm_vnic_tx_dropped",
|
||||||
|
"UCSM Ethernet Tx Dropped counter: total_count",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsRxError: prometheus.NewDesc("ucsm_vnic_rx_error",
|
||||||
|
"UCSM Ethernet Rx Error counter: total_count",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
UcsmVnicStatsTxError: prometheus.NewDesc("ucsm_vnic_tx_error",
|
||||||
|
"UCSM Ethernet Tx Error counter: total_count",
|
||||||
|
[]string{"server", "component", "description"}, nil,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe prometheus describe
|
||||||
|
func (u *UcsExporters) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
log.Printf("Running Describe for UcsExporters\n")
|
||||||
|
|
||||||
|
// UCS Temperatures
|
||||||
|
ch <- u.UcsmTemperatures
|
||||||
|
|
||||||
|
// UCS Network statistics
|
||||||
|
ch <- u.UcsmVnicStatsRxTotalPkts
|
||||||
|
ch <- u.UcsmVnicStatsTxTotalPkts
|
||||||
|
ch <- u.UcsmVnicStatsRxTotalBytes
|
||||||
|
ch <- u.UcsmVnicStatsTxTotalBytes
|
||||||
|
ch <- u.UcsmVnicStatsRxDropped
|
||||||
|
ch <- u.UcsmVnicStatsTxDropped
|
||||||
|
ch <- u.UcsmVnicStatsRxError
|
||||||
|
ch <- u.UcsmVnicStatsTxError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect prometheus collect
|
||||||
|
func (u *UcsExporters) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
|
// TODO - refresh UCS Manager login session
|
||||||
|
|
||||||
|
//var wg = sync.WaitGroup{}
|
||||||
|
g, gCtx := errgroup.WithContext(u.ctx)
|
||||||
|
|
||||||
|
// Create channels to receive values
|
||||||
|
ucsmTempsChannel := make(chan []UcsmTemperatures)
|
||||||
|
ucsmPortStatsChannel := make(chan []UcsmVnicPortStats)
|
||||||
|
|
||||||
|
log.Printf("Running Collect for UCS Temperatures\n")
|
||||||
|
g.Go(func() error {
|
||||||
|
u.GetUcsmTemperatures(gCtx, ucsmTempsChannel)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Printf("Running Collect for UCS Network Statistics\n")
|
||||||
|
g.Go(func() error {
|
||||||
|
u.GetUcsmPortStats(gCtx, ucsmPortStatsChannel)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Receive results from exporter channels
|
||||||
|
ucsmTempResults := <-ucsmTempsChannel
|
||||||
|
ucsmVnicStatsResults := <-ucsmPortStatsChannel
|
||||||
|
|
||||||
|
//wg.Wait()
|
||||||
|
|
||||||
|
// Send results back to prometheus channel
|
||||||
|
for _, blade := range ucsmTempResults {
|
||||||
|
log.Printf("Generating constant metric for component %s with value %f\n", blade.Component, blade.Value)
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmTemperatures, prometheus.GaugeValue, blade.Value, blade.Server, blade.Component, blade.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vnic := range ucsmVnicStatsResults {
|
||||||
|
log.Printf("Generating constant metric for component %s\n", vnic.Component)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsRxTotalPkts, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_rx_total_packets"]), vnic.Server, vnic.Component, "ucsm_vnic_rx_total_packets")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsTxTotalPkts, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_tx_total_packets"]), vnic.Server, vnic.Component, "ucsm_vnic_tx_total_packets")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsRxTotalBytes, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_rx_total_bytes"]), vnic.Server, vnic.Component, "ucsm_vnic_rx_total_bytes")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsTxTotalBytes, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_tx_total_bytes"]), vnic.Server, vnic.Component, "ucsm_vnic_tx_total_bytes")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsRxDropped, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_rx_dropped"]), vnic.Server, vnic.Component, "ucsm_vnic_rx_dropped")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsTxDropped, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_tx_dropped"]), vnic.Server, vnic.Component, "ucsm_vnic_tx_dropped")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsRxError, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_rx_error"]), vnic.Server, vnic.Component, "ucsm_vnic_rx_error")
|
||||||
|
ch <- prometheus.MustNewConstMetric(u.UcsmVnicStatsTxError, prometheus.GaugeValue, float64(vnic.Metrics["ucsm_vnic_tx_error"]), vnic.Server, vnic.Component, "ucsm_vnic_tx_error")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
internal/exporters/structs.go
Normal file
1
internal/exporters/structs.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package exporters
|
@@ -359,6 +359,26 @@ type ProcessorUnit struct {
|
|||||||
Voltage string `xml:"voltage,attr,omitempty"`
|
Voltage string `xml:"voltage,attr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdaptorVnicStats is a managed object representing statistics for a network adaptor
|
||||||
|
// Added by Nathan. Incomplete representation of all data available
|
||||||
|
type AdaptorVnicStats struct {
|
||||||
|
XMLName xml.Name `xml:"adaptorVnicStats"`
|
||||||
|
Dn string `xml:"dn,attr,omitempty"`
|
||||||
|
Rn string `xml:"rn,attr,omitempty"`
|
||||||
|
BytesRx uint64 `xml:"bytesRx,attr,omitempty"`
|
||||||
|
BytesRxDelta uint64 `xml:"bytesRxDelta,attr,omitempty"`
|
||||||
|
BytesTx uint64 `xml:"bytesTx,attr,omitempty"`
|
||||||
|
BytesTxDelta uint64 `xml:"bytesTxDelta,attr,omitempty"`
|
||||||
|
PacketsRx uint64 `xml:"packetsRx,attr,omitempty"`
|
||||||
|
PacketsRxDelta uint64 `xml:"packetsRxDelta,attr,omitempty"`
|
||||||
|
PacketsTx uint64 `xml:"packetsTx,attr,omitempty"`
|
||||||
|
PacketsTxDelta uint64 `xml:"packetsTxDelta,attr,omitempty"`
|
||||||
|
DroppedRx uint64 `xml:"droppedRx,attr,omitempty"`
|
||||||
|
DroppedTx uint64 `xml:"droppedTx,attr,omitempty"`
|
||||||
|
ErrorsRx uint64 `xml:"errorsRx,attr,omitempty"`
|
||||||
|
ErrorsTx uint64 `xml:"errorsTx,attr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// AdaptorUnit is a managed object representing a network adaptor unit such as a
|
// AdaptorUnit is a managed object representing a network adaptor unit such as a
|
||||||
// card that has NIC and/or HBA, SCSI functionality.
|
// card that has NIC and/or HBA, SCSI functionality.
|
||||||
type AdaptorUnit struct {
|
type AdaptorUnit struct {
|
||||||
|
Reference in New Issue
Block a user