Skip to content

Commit d2a16af

Browse files
committed
fix: improve etcd API prefix detection for all versions
1 parent f5eff23 commit d2a16af

2 files changed

Lines changed: 14 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Fixed
1111

12-
- etcd connection failing with 404 on etcd 3.4.x due to hardcoded `/v3/` API prefix
12+
- etcd connection failing with 404 when gRPC gateway uses a different API prefix (auto-detects `/v3/`, `/v3beta/`, `/v3alpha/`)
1313

1414
## [0.21.0] - 2026-03-19
1515

Plugins/EtcdDriverPlugin/EtcdHttpClient.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,14 @@ internal final class EtcdHttpClient: @unchecked Sendable {
415415
let _: EtcdStatusResponse = try await post(path: apiPath("maintenance/status"), body: EmptyBody())
416416
}
417417

418+
/// Probes etcd gateway prefixes in order and selects the first that responds
419+
/// with a non-404 status. Covers all etcd versions:
420+
/// 3.5+ → /v3/ only
421+
/// 3.4 → /v3/ + /v3beta/
422+
/// 3.3 → /v3beta/ + /v3alpha/
423+
/// 3.2- → /v3alpha/ only
418424
private func detectApiPrefix() async throws {
419-
let candidates = ["v3", "v3beta"]
425+
let candidates = ["v3", "v3beta", "v3alpha"]
420426

421427
lock.lock()
422428
guard let session else {
@@ -439,7 +445,8 @@ internal final class EtcdHttpClient: @unchecked Sendable {
439445
do {
440446
(_, response) = try await session.data(for: request)
441447
} catch {
442-
throw EtcdError.connectionFailed(error.localizedDescription)
448+
// Network-level failure — server is unreachable regardless of prefix
449+
throw error
443450
}
444451

445452
guard let httpResponse = response as? HTTPURLResponse else {
@@ -450,16 +457,17 @@ internal final class EtcdHttpClient: @unchecked Sendable {
450457
continue
451458
}
452459

460+
// Any non-404 (200, 401, etc.) means this prefix exists on the server
453461
lock.lock()
454462
apiPrefix = candidate
455463
lock.unlock()
456464
Self.logger.debug("Detected etcd API prefix: \(candidate)")
457465
return
458466
}
459467

460-
lock.lock()
461-
apiPrefix = "v3"
462-
lock.unlock()
468+
throw EtcdError.connectionFailed(
469+
"No supported etcd API found (tried: \(candidates.joined(separator: ", ")))"
470+
)
463471
}
464472

465473
// MARK: - KV Operations

0 commit comments

Comments
 (0)