mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-19 05:36:58 +00:00
fix(rust-volume): parse master lookup when publicUrl is omitted (#10128)
Master /dir/lookup JSON omits publicUrl when empty (Go json omitempty). The Rust volume server required the field, so serde failed with "lookup parse failed: error decoding response body" and cross-DC replicated writes failed. Default publicUrl to empty, fall back to url for peer filtering, and normalize addresses with to_http_address before excluding the local peer (so host:port.grpcPort forms do not match self incorrectly).
This commit is contained in:
@@ -356,12 +356,23 @@ fn parse_url_path(path: &str) -> Option<(VolumeId, NeedleId, Cookie)> {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct VolumeLocation {
|
||||
url: String,
|
||||
#[serde(rename = "publicUrl")]
|
||||
// Master often omits publicUrl when it matches url (Go json omitempty).
|
||||
#[serde(rename = "publicUrl", default)]
|
||||
public_url: String,
|
||||
#[serde(rename = "grpcPort", default)]
|
||||
grpc_port: u32,
|
||||
}
|
||||
|
||||
impl VolumeLocation {
|
||||
fn public_or_url(&self) -> &str {
|
||||
if self.public_url.is_empty() {
|
||||
&self.url
|
||||
} else {
|
||||
&self.public_url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Master /dir/lookup response.
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct LookupResult {
|
||||
@@ -535,9 +546,13 @@ async fn do_replicated_request(
|
||||
.await
|
||||
.map_err(|e| format!("lookup volume failed: {}", e))?;
|
||||
|
||||
let self_http = to_http_address(&state.self_url);
|
||||
let remote_locations: Vec<_> = locations
|
||||
.into_iter()
|
||||
.filter(|loc| loc.url != state.self_url && loc.public_url != state.self_url)
|
||||
.filter(|loc| {
|
||||
to_http_address(&loc.url) != self_http
|
||||
&& to_http_address(loc.public_or_url()) != self_http
|
||||
})
|
||||
.collect();
|
||||
|
||||
if remote_locations.is_empty() {
|
||||
@@ -4022,6 +4037,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Master /dir/lookup often omits publicUrl when empty (Go `json:"publicUrl,omitempty"`).
|
||||
/// Replication must still parse locations or every cross-DC write fails.
|
||||
#[test]
|
||||
fn test_lookup_result_deserializes_without_public_url() {
|
||||
let body = r#"{
|
||||
"volumeOrFileId": "9",
|
||||
"locations": [
|
||||
{"url": "volume-a.example:8080", "dataCenter": "dc-a", "grpcPort": 18080},
|
||||
{"url": "volume-b.example:8080", "dataCenter": "dc-b", "grpcPort": 18080}
|
||||
]
|
||||
}"#;
|
||||
let result: LookupResult = serde_json::from_str(body).expect("parse lookup JSON");
|
||||
let locations = result.locations.expect("locations");
|
||||
assert_eq!(locations.len(), 2);
|
||||
assert_eq!(locations[0].url, "volume-a.example:8080");
|
||||
assert!(locations[0].public_url.is_empty());
|
||||
assert_eq!(locations[0].public_or_url(), "volume-a.example:8080");
|
||||
assert_eq!(locations[0].grpc_port, 18080);
|
||||
}
|
||||
|
||||
/// Regression test for issue #9274.
|
||||
///
|
||||
/// SeaweedFS encodes a server's gRPC port by appending `.grpcPort` to
|
||||
|
||||
Reference in New Issue
Block a user