Skip to content

Add automatic reconnect on Ironic authentication failure#7

Merged
tzumainn merged 1 commit into
osac-project:mainfrom
DanNiESh:ironic-client-reauth
Jun 3, 2026
Merged

Add automatic reconnect on Ironic authentication failure#7
tzumainn merged 1 commit into
osac-project:mainfrom
DanNiESh:ironic-client-reauth

Conversation

@DanNiESh
Copy link
Copy Markdown
Contributor

@DanNiESh DanNiESh commented May 26, 2026

Closes: osac-project/issues#394
When gophercloud's built-in token refresh (ReauthFunc) fails — e.g. due to a network interruption or Keystone being temporarily unavailable — the Ironic client was left permanently stuck with a stale token until the pod restarted. This adds a fallback that detects 401/reauth errors, recreates the service client from scratch, and retries the operation once.

Summary by CodeRabbit

  • New Features

    • Client initialization is now context-aware, supporting timeouts for external calls.
  • Bug Fixes

    • Client detects authentication failures, transparently reconnects the service client, and retries failed operations once—improving reliability and clarifying errors when reconnect or retry fail.
  • Tests

    • Added tests covering auth-error detection, reconnect, and retry behaviors to prevent regressions.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Walkthrough

NewClient now requires a context and retains a newServiceClient factory. The client classifies auth/reauth errors, can reconnect by recreating and validating its ServiceClient, and GetNode/SetPowerState retry once after a successful reconnect. Tests and callsites updated to pass a Context (cmd/main uses a 30s timeout).

Changes

Authentication recovery mechanism for Ironic client

Layer / File(s) Summary
Client imports and factory initialization
internal/ironic/client.go
Adds error, http, and logging imports. Client gains newServiceClient func(ctx context.Context) (*gophercloud.ServiceClient, error) and stores the initial serviceClient. NewClient(ctx) builds the service client via the factory and validates Endpoint.
Auth error detection and reconnect implementation
internal/ironic/client.go
Introduces isAuthError(err error) bool to identify 401/reauth gophercloud errors (including wrapped errors). Adds reconnect(ctx context.Context) error to recreate and validate a new ServiceClient and swap it on success.
API retry integration
internal/ironic/client.go
GetNode and SetPowerState now detect auth errors, log the event, call reconnect, and retry the original operation once after a successful reconnect; errors distinguish reconnect failure from retry failure.
Tests and callsite context updates
internal/ironic/client_internal_test.go, internal/ironic/client_test.go, cmd/main.go
Adds Ginkgo/Gomega tests for isAuthError and reconnect behaviors (including wrapped errors and endpoint validation). Updates tests and cmd/main to construct ironic.NewClient with a context.Context (cmd/main uses a 30s timeout).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Risk Assessment

Severity: Medium-high. Impact: Authentication and availability. The runtime swap of ServiceClient can cause connectivity to an unintended endpoint or leave the client unauthorized if the factory or returned client is misconfigured. Error-classification gaps may lead to missed reconnects or unnecessary retries. Verify factory credentials, Endpoint validation, and that isAuthError covers production auth error shapes.

"When tokens thin and requests stall,
the client rises after auth's fall.
Recreate, validate, then try once more,
baremetal calls resume like before.
Logs hold the tale — reconnect's the chore."


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error PR logs gophercloud errors directly (lines 104, 124, 155), which can include HTTP response bodies and Keystone error details containing sensitive infrastructure information. Sanitize error logging: extract only the error type/code from gophercloud errors rather than logging the full error object which includes response bodies.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Ai-Attribution ⚠️ Warning Commit uses Co-Authored-By for AI tool (Claude Opus 4.6) instead of proper Red Hat attribution (Assisted-by or Generated-by trailer). Replace Co-Authored-By trailer with Assisted-by or Generated-by trailer to properly attribute AI tool usage per Red Hat guidelines.
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding automatic reconnection to handle Ironic authentication failures, which is the core objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets, API keys, tokens, passwords, or credentials found in PR files; all credentials are sourced from environment variables and config files at runtime.
No-Weak-Crypto ✅ Passed No weak cryptographic algorithms (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom crypto implementations, or non-constant-time secret comparisons detected in the PR changes.
No-Injection-Vectors ✅ Passed No SQL, shell, eval, deserialization, or YAML injection vectors detected. User inputs flow only to trusted gophercloud library calls or safe fmt.Errorf formatting.
Container-Privileges ✅ Passed PR modifies only Go source code; no Kubernetes manifests or container configs are changed. Check not applicable.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]
coderabbitai Bot previously requested changes May 26, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/ironic/client_internal_test.go`:
- Around line 129-143: Add a test to cover the case where
Client.newServiceClient returns (nil, nil) to ensure reconnect() handles a nil
*gophercloud.ServiceClient without panicking; update or add a test in
internal/ironic/client_internal_test.go that constructs a Client with
serviceClient set (e.g., oldSC) and newServiceClient returning (nil, nil), then
call c.reconnect() and assert it returns an error containing "no endpoint
configured" (or other expected error) rather than causing a panic, referencing
the Client type and reconnect method so the nil-check path is exercised.

In `@internal/ironic/client.go`:
- Around line 42-43: The code has a data race on Client.serviceClient during
reconnect(): add a synchronization primitive (e.g., a mu sync.RWMutex field on
Client) and use it to protect access: in reconnect() acquire mu.Lock() before
assigning c.serviceClient = sc and mu.Unlock(), and in readers (GetNode,
GetEndpoint, SetPowerState and any immediate retry logic that reads
c.serviceClient) use mu.RLock()/mu.RUnlock() when reading the pointer;
alternatively you can store serviceClient via an atomic.Pointer and do an
atomic.Store/Load around newServiceClient/reads (use
atomic.Pointer[*gophercloud.ServiceClient] if choosing atomics). Ensure the
newServiceClient func and reconnect() still return errors unchanged and that all
reads/writes to serviceClient use the chosen synchronization.
- Around line 65-67: The reconnect path currently uses context.TODO() inside the
factory (clientconfig.NewServiceClient(context.TODO(), "baremetal", nil)) and
reconnect() has no ctx, so reconnection can ignore caller cancellation; modify
reconnect to accept a context (e.g., reconnect(ctx context.Context)), change the
factory in client.go to use the passed ctx instead of context.TODO(), and update
all callers (notably where GetNode and SetPowerState call c.reconnect()) to pass
their request-scoped ctx through so client recreation respects
cancellations/deadlines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 0c2f20cd-d639-4513-bbb4-6f5f9885083e

📥 Commits

Reviewing files that changed from the base of the PR and between 3ad9e1a and 5fb587c.

📒 Files selected for processing (2)
  • internal/ironic/client.go
  • internal/ironic/client_internal_test.go

Comment thread internal/ironic/client_internal_test.go
Comment thread internal/ironic/client.go Outdated
Comment thread internal/ironic/client.go Outdated
@DanNiESh DanNiESh force-pushed the ironic-client-reauth branch 2 times, most recently from 3074ead to c39b355 Compare May 26, 2026 19:31
coderabbitai[bot]
coderabbitai Bot previously requested changes May 26, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
internal/ironic/client.go (2)

42-43: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Synchronize serviceClient access to prevent auth-path data races.

Critical risk / availability impact: reconnect writes c.serviceClient while request paths read it concurrently. Under parallel reconciles, this is a true Go race and can cause undefined behavior during 401 recovery.

Suggested fix
 import (
 	"context"
 	"errors"
 	"fmt"
 	"log/slog"
 	"net/http"
+	"sync"
@@
 	Client struct {
+		mu               sync.RWMutex
 		serviceClient    *gophercloud.ServiceClient
 		newServiceClient func(ctx context.Context) (*gophercloud.ServiceClient, error)
 	}
@@
 func (c *Client) reconnect(ctx context.Context) error {
@@
-	c.serviceClient = sc
+	c.mu.Lock()
+	c.serviceClient = sc
+	c.mu.Unlock()
@@
 func (c *Client) GetNode(ctx context.Context, nodeID string) (*nodes.Node, error) {
-	node, err := nodes.Get(ctx, c.serviceClient, nodeID).Extract()
+	c.mu.RLock()
+	sc := c.serviceClient
+	c.mu.RUnlock()
+	node, err := nodes.Get(ctx, sc, nodeID).Extract()
@@
-			node, err = nodes.Get(ctx, c.serviceClient, nodeID).Extract()
+			c.mu.RLock()
+			sc = c.serviceClient
+			c.mu.RUnlock()
+			node, err = nodes.Get(ctx, sc, nodeID).Extract()
@@
 func (c *Client) GetEndpoint() string {
-	return c.serviceClient.Endpoint
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+	return c.serviceClient.Endpoint
 }
@@
 func (c *Client) SetPowerState(ctx context.Context, nodeID string, target TargetPowerState) error {
-	res := nodes.ChangePowerState(ctx, c.serviceClient, nodeID, nodes.PowerStateOpts{Target: target.powerstate})
+	c.mu.RLock()
+	sc := c.serviceClient
+	c.mu.RUnlock()
+	res := nodes.ChangePowerState(ctx, sc, nodeID, nodes.PowerStateOpts{Target: target.powerstate})
@@
-			res = nodes.ChangePowerState(ctx, c.serviceClient, nodeID, nodes.PowerStateOpts{Target: target.powerstate})
+			c.mu.RLock()
+			sc = c.serviceClient
+			c.mu.RUnlock()
+			res = nodes.ChangePowerState(ctx, sc, nodeID, nodes.PowerStateOpts{Target: target.powerstate})
#!/bin/bash
# Verify unsynchronized serviceClient access sites in this file.
rg -n 'serviceClient' internal/ironic/client.go
rg -n 'sync\.RWMutex|mu\.(RLock|RUnlock|Lock|Unlock)' internal/ironic/client.go

Also applies to: 96-107, 113-114, 120-120, 132-132, 143-143, 150-150

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/ironic/client.go` around lines 42 - 43, The code currently performs
unsynchronized reads/writes of the c.serviceClient field causing data races; add
a sync.RWMutex (e.g., mu) to the client struct and wrap all accesses to
serviceClient: use mu.Lock()/mu.Unlock() when assigning in reconnect (or any
writer like newServiceClient usage) and mu.RLock()/mu.RUnlock() for all readers
in request paths and helper methods that reference serviceClient (search for
uses in reconnect, methods that call c.serviceClient, and any code paths around
token/401 recovery) to ensure safe concurrent access.

68-73: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add nil guards before dereferencing recreated/created service clients.

Major risk / reliability impact: both constructor and reconnect dereference sc.Endpoint without checking sc != nil; a (nil, nil) factory return panics and can crash the process on the recovery path.

Suggested fix
 	sc, err := factory(ctx)
 	if err != nil {
 		return nil, fmt.Errorf("failed to create baremetal client: %w", err)
 	}
+	if sc == nil {
+		return nil, fmt.Errorf("failed to create baremetal client: nil service client")
+	}
 	if sc.Endpoint == "" {
 		return nil, fmt.Errorf("baremetal client has no endpoint configured")
 	}
@@
 	sc, err := c.newServiceClient(ctx)
 	if err != nil {
 		slog.Error("failed to recreate ironic service client", "error", err)
 		return fmt.Errorf("failed to recreate baremetal client: %w", err)
 	}
+	if sc == nil {
+		return fmt.Errorf("failed to recreate baremetal client: nil service client")
+	}
 	if sc.Endpoint == "" {
 		return fmt.Errorf("recreated baremetal client has no endpoint configured")
 	}
#!/bin/bash
# Verify endpoint dereferences and nil guards around ServiceClient creation/recreation.
rg -n 'factory\(ctx\)|newServiceClient\(ctx\)|Endpoint == ""|sc == nil' internal/ironic/client.go

Also applies to: 98-105

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/ironic/client.go` around lines 68 - 73, The code dereferences
sc.Endpoint without ensuring sc is non-nil (from factory(ctx) and in the
reconnect/newServiceClient paths), so add nil guards: after calling factory(ctx)
or newServiceClient(ctx) check if sc == nil and return a descriptive error
(e.g., "baremetal client creation returned nil service client") before any use
of sc.Endpoint; likewise update the reconnect logic to verify sc != nil before
accessing sc.Endpoint or other fields to avoid panics. Ensure changes reference
the factory(ctx) call, the sc variable, sc.Endpoint usage, and the
reconnect/newServiceClient functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/main.go`:
- Line 237: Replace the unbounded context passed to ironic.NewClient with a
timeout-bound context: create a context via
context.WithTimeout(context.Background(), <timeout>), call ironic.NewClient with
that ctx, and ensure you call cancel() (defer cancel()) to avoid leaks; choose a
sensible timeout (e.g., 15–30s) and add the time import if missing so startup
cannot block indefinitely on network/auth failures when initializing
ironicClient.

---

Duplicate comments:
In `@internal/ironic/client.go`:
- Around line 42-43: The code currently performs unsynchronized reads/writes of
the c.serviceClient field causing data races; add a sync.RWMutex (e.g., mu) to
the client struct and wrap all accesses to serviceClient: use
mu.Lock()/mu.Unlock() when assigning in reconnect (or any writer like
newServiceClient usage) and mu.RLock()/mu.RUnlock() for all readers in request
paths and helper methods that reference serviceClient (search for uses in
reconnect, methods that call c.serviceClient, and any code paths around
token/401 recovery) to ensure safe concurrent access.
- Around line 68-73: The code dereferences sc.Endpoint without ensuring sc is
non-nil (from factory(ctx) and in the reconnect/newServiceClient paths), so add
nil guards: after calling factory(ctx) or newServiceClient(ctx) check if sc ==
nil and return a descriptive error (e.g., "baremetal client creation returned
nil service client") before any use of sc.Endpoint; likewise update the
reconnect logic to verify sc != nil before accessing sc.Endpoint or other fields
to avoid panics. Ensure changes reference the factory(ctx) call, the sc
variable, sc.Endpoint usage, and the reconnect/newServiceClient functions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b3e2bc1f-0ea4-4172-9671-e1d1393f32d9

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb587c and c39b355.

📒 Files selected for processing (4)
  • cmd/main.go
  • internal/ironic/client.go
  • internal/ironic/client_internal_test.go
  • internal/ironic/client_test.go

Comment thread cmd/main.go Outdated
Comment thread internal/ironic/client.go Outdated
Comment thread internal/ironic/client.go
Comment thread internal/ironic/client.go
@DanNiESh DanNiESh force-pushed the ironic-client-reauth branch from c39b355 to c1c260e Compare May 29, 2026 16:06
coderabbitai[bot]
coderabbitai Bot previously requested changes May 29, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/ironic/client.go`:
- Around line 68-73: The code calls factory(ctx) and immediately accesses
sc.Endpoint, which dereferences sc without checking for nil; update both factory
call sites in internal/ironic/client.go to first check if sc == nil after sc,
err := factory(ctx) and if so return a descriptive error (e.g.,
fmt.Errorf("baremetal client factory returned nil ServiceClient")) before any
use of sc.Endpoint or other fields, and keep the existing error wrap for err;
apply the same nil-check guard to the other occurrence where sc is dereferenced
(the second factory(...) call block) to prevent panics during startup or
auth-recovery.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: beb658ec-33a2-4135-bf6a-31c439b0b2a6

📥 Commits

Reviewing files that changed from the base of the PR and between c39b355 and c1c260e.

📒 Files selected for processing (4)
  • cmd/main.go
  • internal/ironic/client.go
  • internal/ironic/client_internal_test.go
  • internal/ironic/client_test.go

Comment thread internal/ironic/client.go
@larsks larsks self-requested a review May 29, 2026 17:47
@DanNiESh DanNiESh force-pushed the ironic-client-reauth branch 2 times, most recently from 0cc57ff to 636c785 Compare May 29, 2026 19:16
coderabbitai[bot]
coderabbitai Bot previously requested changes May 29, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
internal/ironic/client_internal_test.go (1)

135-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing test coverage for nil ServiceClient return remains unaddressed.

Security risk: If newServiceClient factory returns (nil, nil) and the implementation dereferences client.Endpoint without a nil-check, this causes a panic. In production, panics reduce availability and create a potential denial-of-service vector if the factory has a bug.

Impact: Availability degradation; untested edge case could cause crash loops during auth failures.

🛡️ Proposed additional test case
+	It("should return error when factory returns nil client", func() {
+		oldSC := &gophercloud.ServiceClient{Endpoint: oldEndpoint}
+
+		c := &Client{
+			serviceClient: oldSC,
+			newServiceClient: func(context.Context) (*gophercloud.ServiceClient, error) {
+				return nil, nil
+			},
+		}
+
+		err := c.reconnect(context.Background())
+		Expect(err).To(HaveOccurred())
+		Expect(err.Error()).To(ContainSubstring("nil service client"))
+		Expect(c.serviceClient).To(Equal(oldSC), "should keep old client on failure")
+	})
+
 	It("should return error when new client has empty endpoint", func() {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/ironic/client_internal_test.go` around lines 135 - 149, The test
suite and reconnect logic must handle the case where newServiceClient returns
(nil, nil); add a test in internal/ironic/client_internal_test.go that sets
Client.newServiceClient to return (nil, nil) and assert that
Client.reconnect(ctx) returns a non-nil error containing a clear message (e.g.,
"no endpoint configured" or "service client is nil"); then update the
Client.reconnect implementation to check the returned *gophercloud.ServiceClient
for nil before dereferencing client.Endpoint (references: Client.reconnect,
Client.newServiceClient, Client.serviceClient, ServiceClient.Endpoint) so it
returns a safe error instead of panicking.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/ironic/client.go`:
- Around line 81-94: The isAuthError function currently uses value targets for
errors.As which misses pointer-typed gophercloud reauth errors; change the
errors.As checks in isAuthError to use pointer targets (e.g.,
*gophercloud.ErrUnableToReauthenticate and
*gophercloud.ErrErrorAfterReauthentication) so pointer instances returned by
ProviderClient are matched, and update tests in client_internal_test.go to
construct the actual pointer-shaped errors (use
&gophercloud.ErrUnableToReauthenticate{...} and
&gophercloud.ErrErrorAfterReauthentication{...}) to verify the real runtime
shapes trigger reconnect.

---

Duplicate comments:
In `@internal/ironic/client_internal_test.go`:
- Around line 135-149: The test suite and reconnect logic must handle the case
where newServiceClient returns (nil, nil); add a test in
internal/ironic/client_internal_test.go that sets Client.newServiceClient to
return (nil, nil) and assert that Client.reconnect(ctx) returns a non-nil error
containing a clear message (e.g., "no endpoint configured" or "service client is
nil"); then update the Client.reconnect implementation to check the returned
*gophercloud.ServiceClient for nil before dereferencing client.Endpoint
(references: Client.reconnect, Client.newServiceClient, Client.serviceClient,
ServiceClient.Endpoint) so it returns a safe error instead of panicking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 343190ff-64d0-4747-9333-bc7f416ce850

📥 Commits

Reviewing files that changed from the base of the PR and between c1c260e and 0cc57ff.

📒 Files selected for processing (4)
  • cmd/main.go
  • internal/ironic/client.go
  • internal/ironic/client_internal_test.go
  • internal/ironic/client_test.go

Comment thread internal/ironic/client.go
When gophercloud's built-in token refresh (ReauthFunc) fails — e.g. due
to a network interruption or Keystone being temporarily unavailable — the
Ironic client was left permanently stuck with a stale token until the pod
restarted. This adds a fallback that detects 401/reauth errors, recreates
the service client from scratch, and retries the operation once.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@DanNiESh DanNiESh force-pushed the ironic-client-reauth branch from 636c785 to 4373790 Compare June 2, 2026 18:55
@coderabbitai coderabbitai Bot dismissed stale reviews from themself June 3, 2026 18:39

Deferring the data race fix to a future PR as agreed with the author.

@tzumainn tzumainn merged commit c585d85 into osac-project:main Jun 3, 2026
5 checks passed
DanNiESh added a commit to DanNiESh/host-management-openstack that referenced this pull request Jun 5, 2026
Port the reconnect logic from the old internal/ironic package (PR osac-project#7)
into the new internal/management layer. When gophercloud's built-in
token refresh fails, the client detects auth errors (401, reauth
failures), recreates the service client from scratch, and retries
the operation once.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tzumainn pushed a commit that referenced this pull request Jun 5, 2026
Port the reconnect logic from the old internal/ironic package (PR #7)
into the new internal/management layer. When gophercloud's built-in
token refresh fails, the client detects auth errors (401, reauth
failures), recreates the service client from scratch, and retries
the operation once.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BMF operators irrevocably fail if Ironic client throws an error

3 participants