Support configurable S3 addressing style - #176
Conversation
|
🔍 OpenCodeReview found 1 issue(s) in this PR.
|
| /// Bucket addressing style: `"virtual"`, `"path"`, or empty to use | ||
| /// endpoint-based auto-detection. | ||
| pub default_addressing_style: String, |
There was a problem hiding this comment.
This public field has only three valid states (auto, virtual, and path), but String makes every other value representable and requires the same parsing/validation contract to be duplicated in validate_global_config and the OSS backend. Prefer a typed enum (for example, Option<AddressingStyle>, where None means auto-detect) with Serde renames for virtual and path; invalid values will then be rejected during deserialization and direct Rust callers cannot construct an invalid config.
Suggestion:
| /// Bucket addressing style: `"virtual"`, `"path"`, or empty to use | |
| /// endpoint-based auto-detection. | |
| pub default_addressing_style: String, | |
| /// Bucket addressing style; `None` uses endpoint-based auto-detection. | |
| pub default_addressing_style: Option<AddressingStyle>, |
| assert!( | ||
| request_line.contains("/127/layers/explicit-style-object"), | ||
| "expected a path-style request for bucket '127', got: {request_line}" | ||
| ); | ||
| assert!( | ||
| request_line.starts_with("GET "), | ||
| "expected a range GET request, got: {request_line}" | ||
| ); |
There was a problem hiding this comment.
Match the request line exactly (or parse its method and request target separately). The current independent contains/starts_with checks would accept an absolute-form URI, an unexpected path prefix/suffix, or another malformed target, so the test could pass without proving that path-style addressing generated exactly /127/layers/explicit-style-object. Also, the assertion message says “range GET” without checking the Range header.
Suggestion:
| assert!( | |
| request_line.contains("/127/layers/explicit-style-object"), | |
| "expected a path-style request for bucket '127', got: {request_line}" | |
| ); | |
| assert!( | |
| request_line.starts_with("GET "), | |
| "expected a range GET request, got: {request_line}" | |
| ); | |
| assert_eq!( | |
| request_line, | |
| "GET /127/layers/explicit-style-object HTTP/1.1", | |
| "expected an exact path-style request target" | |
| ); | |
| assert!( | |
| head.lines() | |
| .any(|line| line.eq_ignore_ascii_case("Range: bytes=0-3")), | |
| "expected a range request, got request head: {head}" | |
| ); |
821e24e to
412e0be
Compare
| assert!( | ||
| request_line.contains("/test-bucket/layers/explicit-style-object"), | ||
| "expected a path-style request for bucket 'test-bucket', got: {request_line}" | ||
| ); |
There was a problem hiding this comment.
This substring check can pass for an incorrect request target, such as a duplicated bucket/path prefix, an absolute-form URI, or an unexpected suffix/query. Since this test is intended as wire-level proof of path-style addressing, parse the request line and assert the method and request target exactly.
Suggestion:
| assert!( | |
| request_line.contains("/test-bucket/layers/explicit-style-object"), | |
| "expected a path-style request for bucket 'test-bucket', got: {request_line}" | |
| ); | |
| let mut request_parts = request_line.split_whitespace(); | |
| assert_eq!(request_parts.next(), Some("GET")); | |
| assert_eq!( | |
| request_parts.next(), | |
| Some("/test-bucket/layers/explicit-style-object") | |
| ); | |
| assert_eq!(request_parts.next(), Some("HTTP/1.1")); | |
| assert_eq!(request_parts.next(), None); |
Propagate the optional override through the snapshot client and OverlayBD runtime while preserving endpoint-based auto-detection by default.
412e0be to
b7dcd59
Compare
| let config = OssConfig { | ||
| enable: true, | ||
| access_key_id: "test-access-key".to_string(), | ||
| secret_access_key: "test-secret-key".to_string(), | ||
| default_region: "auto".to_string(), | ||
| default_endpoint: format!("http://test-bucket.localhost:{port}"), | ||
| default_addressing_style: "path".to_string(), | ||
| timeout_secs: 5, | ||
| retry_count: 1, | ||
| ..Default::default() | ||
| }; |
There was a problem hiding this comment.
This direct struct construction bypasses the runtime JSON/serde boundary for ossConfig.defaultAddressingStyle, although the test claims to prove propagation from that external setting to the wire. A regression in the camelCase mapping or generated runtime configuration could therefore leave the deployed option ineffective while this test still passes. Deserialize an OssConfig (or GlobalConfig) containing "defaultAddressingStyle": "path" before creating the backend so the wire assertion covers the configuration boundary too.
Suggestion:
| let config = OssConfig { | |
| enable: true, | |
| access_key_id: "test-access-key".to_string(), | |
| secret_access_key: "test-secret-key".to_string(), | |
| default_region: "auto".to_string(), | |
| default_endpoint: format!("http://test-bucket.localhost:{port}"), | |
| default_addressing_style: "path".to_string(), | |
| timeout_secs: 5, | |
| retry_count: 1, | |
| ..Default::default() | |
| }; | |
| let config: OssConfig = serde_json::from_value(serde_json::json!({ | |
| "enable": true, | |
| "accessKeyId": "test-access-key", | |
| "secretAccessKey": "test-secret-key", | |
| "defaultRegion": "auto", | |
| "defaultEndpoint": format!("http://test-bucket.localhost:{port}"), | |
| "defaultAddressingStyle": "path", | |
| "timeoutSecs": 5, | |
| "retryCount": 1 | |
| })) | |
| .expect("deserialize OSS runtime config"); |
Summary
Add an optional OSS/S3 bucket addressing-style override and propagate it through both snapshot data paths.
Motivation
The existing OSS backend chooses the addressing style from the endpoint:
Some S3-compatible providers require or prefer virtual-host addressing but cannot be identified reliably by the endpoint heuristic. Without an explicit override, those providers may generate invalid requests.
This change allows users to explicitly select the required addressing style.
Changes
backend.oss.addressing_styleconfiguration:virtualpathossConfig.defaultAddressingStyle.Hostheader.Configuration example
When
addressing_styleis omitted, the existing endpoint-based detection remains unchanged.Backward compatibility
Existing configurations do not require any migration.
The default behavior is preserved:
This change does not modify Prometheus metrics or the
/metricsendpoints.Validation
The following checks pass locally:
cargo fmt --all -- --checkgit diff --checkcargo test -p object-store-operatorcargo clippy -p object-store-operator --all-targets -- -D warningsThe full AgentENV and OverlayBD test suites require a Linux environment. They could not be run locally on macOS because the workspace's
io-uringdependency uses Linux-only libc symbols. Linux CI is required for the full workspace verification.Relationship to #23
This PR supersedes #23.
The original requirement and initial implementation were proposed by @davidmyriel in #23. Thank you for that work and for the original motivation behind the change.
This PR carries the same behavior forward on top of the current
mainbranch, with a refreshed implementation, focused regression tests, and updated documentation. The current implementation was reorganized to fit the latest codebase while preserving the original user-facing intent.