Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ log is based on the [Keep a CHANGELOG](http://keepachangelog.com/) project.

## Unreleased

## [0.18.2]

## Fixed

- Invalid credentials not reported when fetching secrets from vault [#162](https://github.com/Comcast/fishymetrics/issues/162)

## [0.18.1]

## Added
Expand Down
5 changes: 3 additions & 2 deletions common/util.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Comcast Cable Communications Management, LLC
* Copyright 2026 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@ import (

var (
ErrInvalidCredential = errors.New("invalid credential")
ExtraParamsAliases = make(map[string]string)
)

type metricHandler func([]byte) error
Expand Down Expand Up @@ -74,7 +75,7 @@ func Fetch(uri, host, profile string, client *retryablehttp.Client) func() ([]by
delete(ChassisCreds.Creds, host)
ChassisCreds.mu.Unlock()

credential, err := ChassisCreds.GetCredentials(context.Background(), profile, host)
credential, err := ChassisCreds.GetCredentials(context.Background(), profile, host, UpdateCredProfilePath(ExtraParamsAliases))
if err != nil {
return nil, fmt.Errorf("issue retrieving credentials from vault using target: %s", host)
}
Expand Down
28 changes: 14 additions & 14 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024 Comcast Cable Communications Management, LLC
* Copyright 2026 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -159,7 +159,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
return &exp, nil
}

chassisEndpoints, err := getMemberUrls(exp.url+uri+"/Chassis/", target, retryClient)
chassisEndpoints, err := getMemberUrls(exp.url+uri+"/Chassis/", target, profile, retryClient)
if err != nil {
log.Error("error when getting chassis url", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
if errors.Is(err, common.ErrInvalidCredential) {
Expand All @@ -180,7 +180,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud

log.Debug("chassis endpoints response", zap.Strings("chassis_endpoints", chassisEndpoints), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))

mgrEndpoints, err := getMemberUrls(exp.url+uri+"/Managers/", target, retryClient)
mgrEndpoints, err := getMemberUrls(exp.url+uri+"/Managers/", target, profile, retryClient)
if err != nil {
log.Error("error when getting manager endpoint", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand Down Expand Up @@ -214,7 +214,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud

// chassis endpoint to use for obtaining url endpoints for storage controller, NVMe drive metrics as well as the starting
// point for the systems and manager endpoints
sysEndpoints, err := getSystemEndpoints(chasUrlsFinal, target, retryClient, excludes)
sysEndpoints, err := getSystemEndpoints(chasUrlsFinal, target, profile, retryClient, excludes)
if err != nil {
log.Error("error when getting chassis endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -224,7 +224,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
if len(sysEndpoints.storageController) > 0 {
var controllerOutput oem.System
for _, controller := range sysEndpoints.storageController {
controllerOutput, err = getSystemsMetadata(exp.url+controller, target, retryClient)
controllerOutput, err = getSystemsMetadata(exp.url+controller, target, profile, retryClient)
if err != nil {
log.Error("error when getting storage controller metadata", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -246,7 +246,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud

if len(sysEndpoints.volumes) > 0 {
for _, volume := range sysEndpoints.volumes {
virtualDrives, err := getMemberUrls(exp.url+volume, target, retryClient)
virtualDrives, err := getMemberUrls(exp.url+volume, target, profile, retryClient)
if err != nil {
log.Error("error when getting virtual drive member urls", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand Down Expand Up @@ -278,7 +278,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
var dimms, processors oem.Collection
if len(sysEndpoints.systems) > 0 {
// call /redfish/v1/Systems/XXXXX/ for BIOS, Serial number
sysResp, err = getSystemsMetadata(exp.url+sysEndpoints.systems[0], target, retryClient)
sysResp, err = getSystemsMetadata(exp.url+sysEndpoints.systems[0], target, profile, retryClient)
if err != nil {
log.Error("error when getting BIOS version", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -297,15 +297,15 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
// DIMM endpoints array
var systemMemoryEndpoint = GetMemoryURL(sysResp)
if systemMemoryEndpoint != "" {
dimms, err = getDIMMEndpoints(exp.url+systemMemoryEndpoint, target, retryClient)
dimms, err = getDIMMEndpoints(exp.url+systemMemoryEndpoint, target, profile, retryClient)
if err != nil {
log.Error("error when getting DIMM endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
}
}

// CPU processor metrics
processors, err = getProcessorEndpoints(exp.url+sysEndpoints.systems[0]+"Processors/", target, retryClient)
processors, err = getProcessorEndpoints(exp.url+sysEndpoints.systems[0]+"Processors/", target, profile, retryClient)
if err != nil {
log.Error("error when getting Processors endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -319,7 +319,7 @@ 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, excludes)
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+ss, target, profile, retryClient, excludes)
if err != nil {
log.Error("error when getting drive endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -329,7 +329,7 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
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, excludes)
driveEndpointsResp, err = getAllDriveEndpoints(ctx, exp.url, exp.url+url, target, profile, retryClient, excludes)
if err != nil {
log.Error("error when getting drive endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand All @@ -350,20 +350,20 @@ func NewExporter(ctx context.Context, target, uri, profile, model string, exclud
tasks = append(tasks, pool.NewTask(common.Fetch(exp.url+systemFML, target, profile, retryClient), exp.url+systemFML, handle(&exp, FIRMWAREINVENTORY)))
} else {
// Check for /redfish/v1/Managers/XXXX/UpdateService/ for firmware inventory URL
rootComponents, err := getSystemsMetadata(exp.url+uri, target, retryClient)
rootComponents, err := getSystemsMetadata(exp.url+uri, target, profile, retryClient)
if err != nil {
log.Error("error when getting root components metadata", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
}
if rootComponents.UpdateService.URL != "" {
updateServiceEndpoints, err := getSystemsMetadata(exp.url+rootComponents.UpdateService.URL, target, retryClient)
updateServiceEndpoints, err := getSystemsMetadata(exp.url+rootComponents.UpdateService.URL, target, profile, retryClient)
if err != nil {
log.Error("error when getting update service metadata", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
}

if len(updateServiceEndpoints.FirmwareInventory.LinksURLSlice) == 1 {
firmwareInventoryEndpoints, err = getMemberUrls(exp.url+updateServiceEndpoints.FirmwareInventory.LinksURLSlice[0], target, retryClient)
firmwareInventoryEndpoints, err = getMemberUrls(exp.url+updateServiceEndpoints.FirmwareInventory.LinksURLSlice[0], target, profile, retryClient)
if err != nil {
log.Error("error when getting firmware inventory endpoints", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return nil, err
Expand Down
44 changes: 22 additions & 22 deletions exporter/helpers.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2025 Comcast Cable Communications Management, LLC
* Copyright 2026 Comcast Cable Communications Management, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,12 +30,12 @@ import (
"go.uber.org/zap"
)

func getMemberUrls(url, host string, client *retryablehttp.Client) ([]string, error) {
func getMemberUrls(url, host string, profile string, client *retryablehttp.Client) ([]string, error) {
var coll oem.Collection
var urls []string

// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand All @@ -56,13 +56,13 @@ func getMemberUrls(url, host string, client *retryablehttp.Client) ([]string, er
return urls, nil
}

func getSystemEndpoints(chassisUrls []string, host string, client *retryablehttp.Client, excludes Excludes) (SystemEndpoints, error) {
func getSystemEndpoints(chassisUrls []string, host string, profile string, client *retryablehttp.Client, excludes Excludes) (SystemEndpoints, error) {
var chas oem.Chassis
var sysEnd SystemEndpoints

for _, url := range chassisUrls {
// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand Down Expand Up @@ -190,11 +190,11 @@ func getSystemEndpoints(chassisUrls []string, host string, client *retryablehttp
return sysEnd, nil
}

func getSystemsMetadata(url, host string, client *retryablehttp.Client) (oem.System, error) {
func getSystemsMetadata(url, host string, profile string, client *retryablehttp.Client) (oem.System, error) {
var sys oem.System

// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand All @@ -211,11 +211,11 @@ func getSystemsMetadata(url, host string, client *retryablehttp.Client) (oem.Sys
return sys, nil
}

func getDIMMEndpoints(url, host string, client *retryablehttp.Client) (oem.Collection, error) {
func getDIMMEndpoints(url, host string, profile string, client *retryablehttp.Client) (oem.Collection, error) {
var dimms oem.Collection

// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand All @@ -235,11 +235,11 @@ func getDIMMEndpoints(url, host string, client *retryablehttp.Client) (oem.Colle
// The getDriveEndpoint function is used in a recursive fashion to get the body response
// of any type of drive, NVMe, Physical DiskDrives, or Logical Drives, using the GenericDrive struct
// This is used to find the final drive endpoints to append to the task pool for final scraping.
func getDriveEndpoint(url, host string, client *retryablehttp.Client) (oem.GenericDrive, error) {
func getDriveEndpoint(url, host string, profile string, client *retryablehttp.Client) (oem.GenericDrive, error) {
var drive oem.GenericDrive

// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand All @@ -256,11 +256,11 @@ 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, excludes Excludes) (DriveEndpoints, error) {
func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, profile 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
driveResp, err := getDriveEndpoint(initialUrl, host, client)
driveResp, err := getDriveEndpoint(initialUrl, host, profile, client)
if err != nil {
log.Error("api call "+initialUrl+" failed - ", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -270,7 +270,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
for _, member := range driveResp.Members {
// for each ArrayController URL, get the JSON object
// /redfish/v1/Systems/XXXX/SmartStorage/ArrayControllers/X/
arrayCtrlResp, err := getDriveEndpoint(fqdn+member.URL, host, client)
arrayCtrlResp, err := getDriveEndpoint(fqdn+member.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+member.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -293,7 +293,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
if len(arrayCtrlResp.Volumes.LinksURLSlice) > 0 {
for _, volume := range arrayCtrlResp.Volumes.LinksURLSlice {
url := appendSlash(volume)
volumeOutput, err := getDriveEndpoint(fqdn+url, host, client)
volumeOutput, err := getDriveEndpoint(fqdn+url, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+url+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -310,7 +310,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
}

if arrayCtrlResp.Controllers.URL != "" {
controllerOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.Controllers.URL, host, client)
controllerOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.Controllers.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.Controllers.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -328,7 +328,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
// all other servers apart from iLO6
// If LogicalDrives is present, parse logical drive endpoint until all urls are found
if arrayCtrlResp.LinksUpper.LogicalDrives.URL != "" {
logicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksUpper.LogicalDrives.URL, host, client)
logicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksUpper.LogicalDrives.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.LinksUpper.LogicalDrives.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -343,7 +343,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl

// If PhysicalDrives is present, parse physical drive endpoint until all urls are found
if arrayCtrlResp.LinksUpper.PhysicalDrives.URL != "" {
physicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksUpper.PhysicalDrives.URL, host, client)
physicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksUpper.PhysicalDrives.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.LinksUpper.PhysicalDrives.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -356,7 +356,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl

// If LogicalDrives is present, parse logical drive endpoint until all urls are found
if arrayCtrlResp.LinksLower.LogicalDrives.URL != "" {
logicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksLower.LogicalDrives.URL, host, client)
logicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksLower.LogicalDrives.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.LinksLower.LogicalDrives.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -371,7 +371,7 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl

// If PhysicalDrives is present, parse physical drive endpoint until all urls are found
if arrayCtrlResp.LinksLower.PhysicalDrives.URL != "" {
physicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksLower.PhysicalDrives.URL, host, client)
physicalDriveOutput, err := getDriveEndpoint(fqdn+arrayCtrlResp.LinksLower.PhysicalDrives.URL, host, profile, client)
if err != nil {
log.Error("api call "+fqdn+arrayCtrlResp.LinksLower.PhysicalDrives.URL+" failed", zap.Error(err), zap.Any("trace_id", ctx.Value(logging.TraceIDKey("traceID"))))
return driveEndpoints, err
Expand All @@ -386,11 +386,11 @@ func getAllDriveEndpoints(ctx context.Context, fqdn, initialUrl, host string, cl
return driveEndpoints, nil
}

func getProcessorEndpoints(url, host string, client *retryablehttp.Client) (oem.Collection, error) {
func getProcessorEndpoints(url, host string, profile string, client *retryablehttp.Client) (oem.Collection, error) {
var processors oem.Collection

// Use centralized HTTP client with credential rotation
fetch := common.Fetch(url, host, "", client)
fetch := common.Fetch(url, host, profile, client)
body, err := fetch()
if err != nil {
if errors.Is(err, common.ErrInvalidCredential) {
Expand Down
Loading