diff --git a/README.md b/README.md index f238b3285ec2de0f342ec43176185d0f967c77b6..3c999701ce5f5de9f6c75e1af6f7713fef0e4500 100644 --- a/README.md +++ b/README.md @@ -24,5 +24,7 @@ Metric | Type | Description `nexenta_jbod_temp` | gauge | Temperature of JBOD (°C) `nexenta_jbod_voltage` | gauge | Voltage of JBOD (Volts) `nexenta_jbod_slot_status` | gauge | Status of JBOD slot (0/1) -`nexenta_volume_status` | gauge | Is the volume online (0/1) `nexenta_license_days_left` | gauge | License days left +`nexenta_volume_status` | gauge | Is the volume online (0/1) +`nexenta_volume_lun_status` | gauge | Is the volume LUN online (or available, if spare)(0/1) + diff --git a/main.go b/main.go index 5e550abb25e48ace27a343c8f495a1c1512de392..faee1a20413db4738dcee4ca0874d03f479d9fc0 100644 --- a/main.go +++ b/main.go @@ -78,12 +78,15 @@ type Exporter struct { up *prometheus.Desc scrapeFailures prometheus.Counter - volumeStatus *prometheus.Desc + jbodStatus *prometheus.Desc jbodTemp *prometheus.Desc jbodVoltage *prometheus.Desc jbodSlotStatus *prometheus.Desc licenseDaysLeft *prometheus.Desc + volumeStatus *prometheus.Desc + volumeLunStatus *prometheus.Desc + } func NewExporter(uri string) *Exporter { @@ -101,12 +104,6 @@ func NewExporter(uri string) *Exporter { Help: "Number of errors while scraping the Nexenta API", ConstLabels: prometheus.Labels{"host":*apiHost}, }), - volumeStatus: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "volume", "status"), - "Status of volume.", - []string{"volume", "state", "errors"}, - prometheus.Labels{"host":*apiHost}, - ), jbodStatus: prometheus.NewDesc( prometheus.BuildFQName(namespace, "jbod", "status"), "Status of JBOD.", @@ -137,6 +134,18 @@ func NewExporter(uri string) *Exporter { nil, prometheus.Labels{"host":*apiHost}, ), + volumeStatus: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "volume", "status"), + "Status of volume.", + []string{"volume", "state", "errors"}, + prometheus.Labels{"host":*apiHost}, + ), + volumeLunStatus: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "volume", "lun_status"), + "Status of volume LUN.", + []string{"volume", "lun", "state", "errors", "group"}, + prometheus.Labels{"host":*apiHost}, + ), client: &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecure}, @@ -148,11 +157,12 @@ func NewExporter(uri string) *Exporter { func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { ch <- e.up e.scrapeFailures.Describe(ch) - ch <- e.volumeStatus ch <- e.jbodStatus ch <- e.jbodTemp ch <- e.jbodVoltage ch <- e.jbodSlotStatus + ch <- e.volumeStatus + ch <- e.volumeLunStatus } func (e *Exporter) Collect(ch chan<- prometheus.Metric) { @@ -182,6 +192,10 @@ func (e *Exporter) collect(ch chan<- prometheus.Metric) error { if err != nil { return fmt.Errorf("getVolumeStatus(): %v", err) } + err = e.getVolumeLuns(ch, volume) + if err != nil { + return fmt.Errorf("getVolumeLuns(): %v", err) + } } } @@ -238,6 +252,36 @@ func (e *Exporter) getVolumeStatus(ch chan<- prometheus.Metric, volume string) e return err } +func (e *Exporter) getVolumeLuns(ch chan<- prometheus.Metric, volume string) error { + + apiResponse, err := e.queryApi(ch, "volume", "get_luns", []string{volume}); if err != nil { return err } + apiResult, err := json.Marshal(apiResponse.Result); if err != nil { return err } + + var volumeLuns map[string][]string + err = json.Unmarshal(apiResult, &volumeLuns); if err != nil { return err } + + for lun, data := range volumeLuns { + // data: 0=state, 1=err_read, 2=err_write, 3=err_chksum, 4=?, 5=group, 6=? + var volumeLunStatus float64 = 0 + var volumeLunErrors float64 = 0 + errorsRead, _ := strconv.ParseFloat(data[1], 64) + errorsWrite, _ := strconv.ParseFloat(data[2], 64) + errorsChksum, _ := strconv.ParseFloat(data[3], 64) + volumeLunErrors = errorsRead + errorsWrite + errorsChksum + labelErrors := strconv.FormatFloat(volumeLunErrors, 'f', 0, 64) + if len(data) > 0 { + if (data[5] != "spares" && data[0] == "ONLINE") || + (data[5] == "spares" && data[0] == "AVAIL") { + volumeLunStatus = 1 + } + } + ch <- prometheus.MustNewConstMetric(e.volumeLunStatus, prometheus.GaugeValue, volumeLunStatus, + volume, lun, data[0], labelErrors, data[5]) + } + + return err +} + func (e *Exporter) getJBODs(ch chan<- prometheus.Metric) ([]string, error) { apiResponse, err := e.queryApi(ch, "jbod", "get_names", []string{""}); if err != nil { return nil, err }