From d8e2887add15dd9a9b30808ce66fb211a792296c Mon Sep 17 00:00:00 2001 From: Thomas Jegou <34894717+T-jegou@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:57:21 +0200 Subject: [PATCH 1/3] fix(chassis): gracefully handle missing NetworkAdapters link (#437) The Redfish Chassis schema (v1.27.0) defines the NetworkAdapters property as an optional link to a collection of network adapters physically located in the chassis. It is perfectly valid for this property to be omitted when no adapters are present. However, the current implementation of (*Chassis).NetworkAdapters() calls ListReferencedNetworkAdapter even when the link is empty, potentially resulting in 404 errors or misleading failures on otherwise valid systems. This patch introduces an early return when the networkAdapters link is not defined, aligning the behavior with other optional properties such as Power(), Thermal(), and PCIeSlots(). This is particularly relevant for minimal chassis configurations like backplanes or storage components (e.g., ChassisType: "Component" or "Module"), which often appear in the Chassis collection but do not expose network hardware. Reference: https://redfish.dmtf.org/schemas/v1/Chassis.v1_27_0.json --- redfish/chassis.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/redfish/chassis.go b/redfish/chassis.go index f6baa7c7..b257ac05 100644 --- a/redfish/chassis.go +++ b/redfish/chassis.go @@ -816,6 +816,9 @@ func (chassis *Chassis) Switches() ([]*Switch, error) { // NetworkAdapters gets the collection of network adapters of this chassis func (chassis *Chassis) NetworkAdapters() ([]*NetworkAdapter, error) { + if chassis.networkAdapters == "" { + return nil, nil + } return ListReferencedNetworkAdapter(chassis.GetClient(), chassis.networkAdapters) } From 806589a4d166ced8465eabd29d91ed2eecd01c5e Mon Sep 17 00:00:00 2001 From: Sean McGinnis Date: Sat, 28 Jun 2025 08:01:20 -0500 Subject: [PATCH 2/3] Initialize TLSClientConfig when using default transport (#438) To allow insecure (unverified TLS) connections, we need to set a flag allowing it. When using the default http client, or if a supplied client has not been fully configured, the struct containing this flag is not initialized and set to nil in the http client transport. This makes sure the config property is initialized if we are configured to set the flag to avoid nil pointer errors. Signed-off-by: Sean McGinnis --- client.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client.go b/client.go index 0aca0ac2..aef9a2fe 100644 --- a/client.go +++ b/client.go @@ -7,6 +7,7 @@ package gofish import ( "bytes" "context" + "crypto/tls" "encoding/base64" "encoding/json" "fmt" @@ -141,6 +142,13 @@ func setupClientWithConfig(ctx context.Context, config *ClientConfig) (c *APICli // amend its configuration to match what was provided to us if transport, ok := client.HTTPClient.Transport.(*http.Transport); ok { if config.Insecure { + // If we're using the default transport, need to make sure there + // is a TLSClientConfig set in order to set the SkipVerify flag. + if transport.TLSClientConfig == nil { + transport.TLSClientConfig = &tls.Config{ + MinVersion: tls.VersionTLS12, + } + } transport.TLSClientConfig.InsecureSkipVerify = config.Insecure } From c5de04b1432cc459cdbc265cb0f9fb0ce8e113c4 Mon Sep 17 00:00:00 2001 From: Joey Berkovitz Date: Fri, 11 Jul 2025 08:14:15 -0400 Subject: [PATCH 3/3] handle etag properly on CreateAccount call --- common/entity.go | 5 +++++ redfish/accountservice.go | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/common/entity.go b/common/entity.go index f50c32a0..07abed8e 100644 --- a/common/entity.go +++ b/common/entity.go @@ -63,6 +63,11 @@ func (e *Entity) DisableEtagMatch(b bool) { e.disableEtagMatch = b } +// IsEtagMatchDisabled indicates if etag matching is enabled on this entity +func (e *Entity) IsEtagMatchDisabled() bool { + return e.disableEtagMatch +} + // Update commits changes to an entity. func (e *Entity) Update(originalEntity, updatedEntity reflect.Value, allowedUpdates []string) error { payload := getPatchPayloadFromUpdate(originalEntity, updatedEntity) diff --git a/redfish/accountservice.go b/redfish/accountservice.go index 7c6fc0ea..7c83dbdd 100644 --- a/redfish/accountservice.go +++ b/redfish/accountservice.go @@ -6,6 +6,7 @@ package redfish import ( "encoding/json" + "fmt" "reflect" "github.com/stmcginnis/gofish/common" @@ -510,7 +511,22 @@ func (accountservice *AccountService) CreateAccount(userName, password, roleID s Password: password, RoleID: roleID, } - resp, err := accountservice.PostWithResponse(accountservice.accounts, t) + + baseEntity := &accountservice.Entity + + // The proper ETag for creating an account is found at `/AccountService/Accounts` + // If ETag matching is disabled, we don't care and don't need to waste a request, + // but otherwise, we need to load /Accounts to get the ETag then issue the request against that Entity + if !accountservice.IsEtagMatchDisabled() { + accountsEntity, err := common.GetObject[common.Entity](accountservice.GetClient(), accountservice.accounts) + if err != nil { + return nil, fmt.Errorf("failed to get accounts entity: %w", err) + } + + baseEntity = accountsEntity + } + + resp, err := baseEntity.PostWithResponse(accountservice.accounts, t) if err != nil { return nil, err }