Skip to content

Commit

Permalink
Merge pull request #92 from Comcast/storage_controller_vol_drives_ilo…
Browse files Browse the repository at this point in the history
…5_ver3.x

Storage controller vol drives ilo5 ver3.x
  • Loading branch information
ibrahimkk-moideen authored Aug 27, 2024
2 parents beee506 + 6057b9c commit 4c6c78c
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 58 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ log is based on the [Keep a CHANGELOG](http://keepachangelog.com/) project.
- HP DL380 module to include CPU metrics and all HP models to include bayNumber in PSU metrics [#57](https://github.com/Comcast/fishymetrics/issues/57)
- use standard library for http routing instead of gorilla mux package [#47](https://github.com/Comcast/fishymetrics/issues/47)
- Avoid collecting firmware metrics if count of endpoints are 75 or greater [#77] (https://github.com/Comcast/fishymetrics/issues/77)
- Support for physical disk, logical drive and storage controller metrics collection from iLO5 fw ver.3.0.x [#91](https://github.com/Comcast/fishymetrics/issues/91)

## [0.7.1]

Expand Down
20 changes: 11 additions & 9 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,12 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
if len(controllerOutput.Volumes.LinksURLSlice) > 0 {
for _, volume := range controllerOutput.Volumes.LinksURLSlice {
url := appendSlash(volume)
if checkUnique(sysEndpoints.volumes, url) {
sysEndpoints.volumes = append(sysEndpoints.volumes, url)
if reg, ok := excludes["drive"]; ok {
if !reg.(*regexp.Regexp).MatchString(url) {
if checkUnique(sysEndpoints.volumes, url) {
sysEndpoints.volumes = append(sysEndpoints.volumes, url)
}
}
}
}
}
Expand Down Expand Up @@ -319,9 +323,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
if systemMemoryEndpoint != "" {
dimms, err = getDIMMEndpoints(exp.url+systemMemoryEndpoint, target, retryClient)
if err != nil {
log.Error("error when getting DIMM endpoints",
zap.Error(err),
zap.Any("trace_id", ctx.Value("traceID")))
log.Error("error when getting DIMM endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value("traceID")))
return nil, err
}
}
Expand All @@ -341,17 +343,17 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
var ss = GetSmartStorageURL(sysResp)
var driveEndpointsResp DriveEndpoints
if ss != "" {
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+ss, target, retryClient)
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+ss, target, retryClient, excludes)
if err != nil {
log.Error("error when getting drive endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value("traceID")))
return nil, err
}
}

if len(sysEndpoints.storageController) == 0 && ss == "" {
if (len(sysEndpoints.storageController) == 0 && ss == "") || (len(sysEndpoints.drives) == 0 && len(driveEndpointsResp.physicalDriveURLs) == 0) {
if sysResp.Storage.URL != "" {
url := appendSlash(sysResp.Storage.URL)
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+url, target, retryClient)
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+url, target, retryClient, excludes)
if err != nil {
log.Error("error when getting drive endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value("traceID")))
return nil, err
Expand Down Expand Up @@ -418,7 +420,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
}

for _, url := range driveEndpointsResp.physicalDriveURLs {
tasks = append(tasks, pool.NewTask(common.Fetch(exp.url+url, target, profile, retryClient), exp.url+url, handle(&exp, DISKDRIVE)))
tasks = append(tasks, pool.NewTask(common.Fetch(exp.url+url, target, profile, retryClient), exp.url+url, handle(&exp, UNKNOWN_DRIVE)))
}

// drives from this list could either be NVMe or physical SAS/SATA
Expand Down
16 changes: 9 additions & 7 deletions exporter/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,9 @@ func (e *Exporter) exportPhysicalDriveMetrics(body []byte) error {
return fmt.Errorf("Error Unmarshalling DiskDriveMetrics - " + err.Error())
}
// Check physical drive is enabled then check status and convert string to numeric values
if dlphysical.Status.State == "Enabled" {
if dlphysical.Status.State == "Absent" {
return nil
} else if dlphysical.Status.State == "Enabled" {
if dlphysical.Status.Health == "OK" {
state = OK
} else {
Expand Down Expand Up @@ -360,8 +362,8 @@ func (e *Exporter) exportNVMeDriveMetrics(body []byte) error {
}

// Check nvme drive is enabled then check status and convert string to numeric values
if dlnvme.Oem.Hpe.DriveStatus.State == "Enabled" {
if dlnvme.Oem.Hpe.DriveStatus.Health == "OK" {
if dlnvme.Status.State == "Enabled" || dlnvme.Oem.Hpe.DriveStatus.State == "Enabled" {
if dlnvme.Status.Health == "OK" || dlnvme.Oem.Hpe.DriveStatus.Health == "OK" {
state = OK
} else {
state = BAD
Expand All @@ -388,7 +390,7 @@ func (e *Exporter) exportUnknownDriveMetrics(body []byte) error {
if err != nil {
return fmt.Errorf("Error Unmarshalling NVMeDriveMetrics - " + err.Error())
}
} else if protocol.Protocol != "" {
} else {
err = e.exportPhysicalDriveMetrics(body)
if err != nil {
return fmt.Errorf("Error Unmarshalling DiskDriveMetrics - " + err.Error())
Expand Down Expand Up @@ -418,18 +420,18 @@ func (e *Exporter) exportStorageControllerMetrics(body []byte) error {
} else {
state = BAD
}
(*drv)["storageControllerStatus"].WithLabelValues(scm.Name, e.ChassisSerialNumber, e.Model, sc.FirmwareVersion, sc.Model).Set(state)
(*drv)["storageControllerStatus"].WithLabelValues(scm.Name, e.ChassisSerialNumber, e.Model, sc.FirmwareVersion, sc.Model, sc.Location.Location).Set(state)
}
}

if len(scm.StorageController.StorageController) == 0 {
if scm.Status.State == "Enabled" {
if scm.Status.State == "Enabled" && scm.Status.Health != "" {
if scm.Status.Health == "OK" {
state = OK
} else {
state = BAD
}
(*drv)["storageControllerStatus"].WithLabelValues(scm.Name, e.ChassisSerialNumber, e.Model, scm.ControllerFirmware.FirmwareVersion, scm.Model).Set(state)
(*drv)["storageControllerStatus"].WithLabelValues(scm.Name, e.ChassisSerialNumber, e.Model, scm.ControllerFirmware.FirmwareVersion, scm.Model, scm.Location.Location).Set(state)
}
}

Expand Down
35 changes: 25 additions & 10 deletions exporter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func getDriveEndpoint(url, host string, client *retryablehttp.Client) (oem.Gener
return drive, nil
}

func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, client *retryablehttp.Client) (DriveEndpoints, error) {
func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, client *retryablehttp.Client, excludes Excludes) (DriveEndpoints, error) {
var driveEndpoints DriveEndpoints

// Get initial JSON return of /redfish/v1/Systems/XXXX/SmartStorage/ArrayControllers/ set to output
Expand All @@ -348,19 +348,34 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
// /redfish/v1/Systems/XXXX/Storage/XXXXX/
if len(arrayCtrlResp.StorageDrives) > 0 {
for _, member := range arrayCtrlResp.StorageDrives {
driveEndpoints.physicalDriveURLs = append(driveEndpoints.physicalDriveURLs, appendSlash(member.URL))
if reg, ok := excludes["drive"]; ok {
if !reg.(*regexp.Regexp).MatchString(member.URL) {
if checkUnique(driveEndpoints.physicalDriveURLs, member.URL) {
driveEndpoints.physicalDriveURLs = append(driveEndpoints.physicalDriveURLs, appendSlash(member.URL))
}
}
}
}

// If Volumes are present, parse volumes endpoint until all urls are found
if arrayCtrlResp.Volumes.URL != "" {
volumeOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.Volumes.URL, host, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.Volumes.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value("traceID")))
return driveEndpoints, err
}
if len(arrayCtrlResp.Volumes.LinksURLSlice) > 0 {
for _, volume := range arrayCtrlResp.Volumes.LinksURLSlice {
url := appendSlash(volume)
volumeOutput, err := getDriveEndpoint(fqdn+url, host, client)
if err != nil {
log.Error("api call "+fqdn+url+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value("traceID")))
return driveEndpoints, err
}

for _, member := range volumeOutput.Members {
driveEndpoints.logicalDriveURLs = append(driveEndpoints.logicalDriveURLs, appendSlash(member.URL))
for _, member := range volumeOutput.Members {
if reg, ok := excludes["drive"]; ok {
if !reg.(*regexp.Regexp).MatchString(member.URL) {
if checkUnique(driveEndpoints.logicalDriveURLs, member.URL) {
driveEndpoints.logicalDriveURLs = append(driveEndpoints.logicalDriveURLs, appendSlash(member.URL))
}
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion exporter/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func NewDeviceMetrics() *map[string]*metrics {
}

StorageControllerMetrics = &metrics{
"storageControllerStatus": newServerMetric("redfish_storage_controller_status", "Current storage controller status 1 = OK, 0 = BAD", nil, []string{"name", "chassisSerialNumber", "chassisModel", "firmwareVersion", "model"}),
"storageControllerStatus": newServerMetric("redfish_storage_controller_status", "Current storage controller status 1 = OK, 0 = BAD", nil, []string{"name", "chassisSerialNumber", "chassisModel", "firmwareVersion", "model", "location"}),
}

MemoryMetrics = &metrics{
Expand Down
49 changes: 27 additions & 22 deletions oem/drive.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,25 @@ type NVMeDriveMetrics struct {
// Logical Drives
// /redfish/v1/Systems/X/SmartStorage/ArrayControllers/X/LogicalDrives/X/
type LogicalDriveMetrics struct {
Id string `json:"Id"`
CapacityMiB int `json:"CapacityMiB"`
Description string `json:"Description"`
DisplayName string `json:"DisplayName"`
InterfaceType string `json:"InterfaceType"`
Identifiers []Identifiers `json:"Identifiers"`
LogicalDriveName string `json:"LogicalDriveName"`
LogicalDriveNumber int `json:"LogicalDriveNumber"`
Name string `json:"Name"`
Raid string `json:"Raid"`
RaidType string `json:"RAIDType"`
Status Status `json:"Status"`
StripeSizebytes int `json:"StripeSizebytes"`
VolumeUniqueIdentifier string `json:"VolumeUniqueIdentifier"`
Id string `json:"Id"`
CapacityMiB int `json:"CapacityMiB"`
Description string `json:"Description"`
DisplayName string `json:"DisplayName"`
InterfaceType string `json:"InterfaceType"`
Identifiers []Identifiers `json:"Identifiers"`
Links DriveCollection `json:"Links"`
LogicalDriveName string `json:"LogicalDriveName"`
LogicalDriveNumber int `json:"LogicalDriveNumber"`
Name string `json:"Name"`
Raid string `json:"Raid"`
RaidType string `json:"RAIDType"`
Status Status `json:"Status"`
StripeSizebytes int `json:"StripeSizebytes"`
VolumeUniqueIdentifier string `json:"VolumeUniqueIdentifier"`
}

type DriveCollection struct {
DrivesCount int `json:"[email protected]"`
}

type Identifiers struct {
Expand Down Expand Up @@ -123,14 +128,14 @@ func (w *LocationWrapper) UnmarshalJSON(data []byte) error {
// /redfish/v1/Systems/X/SmartStorage/ArrayControllers/ for Logical and Physical Drives
// /redfish/v1/Chassis/X/Drives/ for NVMe Drive(s)
type GenericDrive struct {
Members []Members `json:"Members,omitempty"`
LinksUpper LinksUpper `json:"Links,omitempty"`
LinksLower LinksLower `json:"links,omitempty"`
MembersCount int `json:"[email protected],omitempty"`
DriveCount int `json:"[email protected],omitempty"`
StorageDrives []Link `json:"Drives,omitempty"`
Volumes Link `json:"Volumes,omitempty"`
Controllers Link `json:"Controllers,omitempty"`
Members []Members `json:"Members,omitempty"`
LinksUpper LinksUpper `json:"Links,omitempty"`
LinksLower LinksLower `json:"links,omitempty"`
MembersCount int `json:"[email protected],omitempty"`
DriveCount int `json:"[email protected],omitempty"`
StorageDrives []Link `json:"Drives,omitempty"`
Volumes LinksWrapper `json:"Volumes,omitempty"`
Controllers Link `json:"Controllers,omitempty"`
}

type Members struct {
Expand Down
36 changes: 27 additions & 9 deletions oem/storage_ctrl.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,24 @@ import (
// /redfish/v1/Systems/WZPXXXXX/Storage/MRAID

type StorageControllerMetrics struct {
ControllerFirmware FirmwareVersionWrapper `json:"FirmwareVersion"`
Drives []Drive `json:"Drives"`
Location StorCtrlLocationWrapper `json:"Location"`
Model string `json:"Model"`
Name string `json:"Name"`
StorageController StorageControllerWrapper `json:"StorageControllers"`
Drives []Drive `json:"Drives"`
Status Status `json:"Status"`
Model string `json:"Model"`
ControllerFirmware FirmwareVersionWrapper `json:"FirmwareVersion"`
}

// StorageController contains status metadata of the C220 chassis storage controller
type StorageController struct {
Status Status `json:"Status"`
MemberId string `json:"MemberId"`
Manufacturer string `json:"Manufacturer,omitempty"`
Model string `json:"Model"`
Name string `json:"Name"`
FirmwareVersion string `json:"FirmwareVersion"`
Status Status `json:"Status"`
MemberId string `json:"MemberId"`
Manufacturer string `json:"Manufacturer,omitempty"`
Model string `json:"Model"`
Name string `json:"Name"`
FirmwareVersion string `json:"FirmwareVersion"`
Location StorCtrlLocationWrapper `json:"Location,omitempty"`
}

type StorageControllerSlice struct {
Expand Down Expand Up @@ -108,3 +110,19 @@ type ExtendedInfo struct {
MessageArg []string `json:"MessageArgs"`
Severity string `json:"Severity"`
}

type StorCtrlLocationWrapper struct {
Location string
}

func (w *StorCtrlLocationWrapper) UnmarshalJSON(data []byte) error {
var location PhysicalLocation
err := json.Unmarshal(data, &location)
if err == nil {
w.Location = location.PartLocation.ServiceLabel
} else {
return json.Unmarshal(data, &w.Location)
}

return nil
}

0 comments on commit 4c6c78c

Please sign in to comment.