From 1698009062a8a853ceb036b0a7f9d5d76109e550 Mon Sep 17 00:00:00 2001
From: centra
Date: Tue, 31 Mar 2026 11:14:18 +0900
Subject: [PATCH] Simplify DNS publication state and FlashDNS storage
---
deployer/crates/deployer-types/src/lib.rs | 53 --------------
.../crates/fleet-scheduler/src/publish.rs | 53 +++++++++-----
.../crates/flashdns-server/src/metadata.rs | 69 ++-----------------
nix/test-cluster/run-cluster.sh | 10 +--
4 files changed, 45 insertions(+), 140 deletions(-)
diff --git a/deployer/crates/deployer-types/src/lib.rs b/deployer/crates/deployer-types/src/lib.rs
index ae5c125..3fafaa8 100644
--- a/deployer/crates/deployer-types/src/lib.rs
+++ b/deployer/crates/deployer-types/src/lib.rs
@@ -896,14 +896,8 @@ pub struct PublishedLoadBalancerState {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PublishedDnsRecordState {
pub zone_id: String,
- #[serde(default)]
- pub record_id: String,
- #[serde(default)]
pub record_ids: Vec,
pub fqdn: String,
- #[serde(default)]
- pub value: String,
- #[serde(default)]
pub values: Vec,
}
@@ -921,51 +915,6 @@ pub struct ServicePublicationState {
pub observed_at: Option>,
}
-/// Publication record stored under photoncloud/clusters/{cluster_id}/publications/{service}.
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
-pub struct ServicePublicationRecord {
- #[serde(default)]
- pub service: String,
- #[serde(default)]
- pub org_id: Option,
- #[serde(default)]
- pub project_id: Option,
- #[serde(default)]
- pub lb_id: Option,
- #[serde(default)]
- pub pool_id: Option,
- #[serde(default)]
- pub listener_id: Option,
- #[serde(default)]
- pub vip: Option,
- #[serde(default)]
- pub listener_port: Option,
- #[serde(default)]
- pub listener_protocol: Option,
- #[serde(default)]
- pub pool_protocol: Option,
- #[serde(default)]
- pub backend_ids: HashMap,
- #[serde(default)]
- pub backend_targets: HashMap,
- #[serde(default)]
- pub dns_zone: Option,
- #[serde(default)]
- pub dns_name: Option,
- #[serde(default)]
- pub dns_mode: Option,
- #[serde(default)]
- pub dns_ttl: Option,
- #[serde(default)]
- pub zone_id: Option,
- #[serde(default)]
- pub record_id: Option,
- #[serde(default)]
- pub fqdn: Option,
- #[serde(default)]
- pub updated_at: Option>,
-}
-
/// mTLS policy definition.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct MtlsPolicySpec {
@@ -1222,10 +1171,8 @@ mod tests {
}),
dns: Some(PublishedDnsRecordState {
zone_id: "zone-1".to_string(),
- record_id: "record-1".to_string(),
record_ids: vec!["record-1".to_string()],
fqdn: "api.test.cluster.local".to_string(),
- value: "10.0.0.50".to_string(),
values: vec!["10.0.0.50".to_string()],
}),
observed_at: None,
diff --git a/deployer/crates/fleet-scheduler/src/publish.rs b/deployer/crates/fleet-scheduler/src/publish.rs
index 9012585..bdec3e5 100644
--- a/deployer/crates/fleet-scheduler/src/publish.rs
+++ b/deployer/crates/fleet-scheduler/src/publish.rs
@@ -365,7 +365,6 @@ impl PublicationController {
let zone_name = normalize_zone_name(&spec.zone);
let record_name = record_name_for_service(spec, service);
let fqdn = format!("{}.{}", record_name, zone_name);
- let primary_value = desired_values.first().cloned().unwrap_or_default();
if self.config.dry_run {
info!(
@@ -376,10 +375,8 @@ impl PublicationController {
);
return Ok(existing.cloned().or(Some(PublishedDnsRecordState {
zone_id: String::new(),
- record_id: String::new(),
record_ids: Vec::new(),
fqdn,
- value: primary_value,
values: desired_values,
})));
}
@@ -389,10 +386,11 @@ impl PublicationController {
let zone =
ensure_zone(&mut zone_client, auth_token, &zone_name, org_id, project_id).await?;
+ let replacing_existing =
+ existing.filter(|state| !dns_state_matches_target(state, &zone.id, &fqdn));
let records = ensure_records(
&mut record_client,
auth_token,
- existing,
&zone.id,
&record_name,
spec.ttl,
@@ -403,13 +401,14 @@ impl PublicationController {
.iter()
.map(|record| record.id.clone())
.collect::>();
+ if let Some(previous) = replacing_existing {
+ self.cleanup_dns(auth_token, previous).await?;
+ }
Ok(Some(PublishedDnsRecordState {
zone_id: zone.id,
- record_id: record_ids.first().cloned().unwrap_or_default(),
record_ids,
fqdn,
- value: primary_value,
values: desired_values,
}))
}
@@ -424,9 +423,6 @@ impl PublicationController {
};
let mut record_client = RecordServiceClient::connect(endpoint.clone()).await?;
let mut record_ids = dns_state.record_ids.clone();
- if record_ids.is_empty() && !dns_state.record_id.is_empty() {
- record_ids.push(dns_state.record_id.clone());
- }
record_ids.sort();
record_ids.dedup();
@@ -837,7 +833,6 @@ async fn ensure_zone(
async fn ensure_records(
client: &mut RecordServiceClient,
auth_token: &str,
- existing: Option<&PublishedDnsRecordState>,
zone_id: &str,
name: &str,
ttl: u32,
@@ -860,13 +855,7 @@ async fn ensure_records(
let mut matching = records
.iter()
- .filter(|record| {
- record.name == name
- || existing.map(|state| state.record_id.as_str()) == Some(record.id.as_str())
- || existing
- .map(|state| state.record_ids.iter().any(|id| id == &record.id))
- .unwrap_or(false)
- })
+ .filter(|record| record.name == name)
.cloned()
.collect::>();
matching.sort_by(|lhs, rhs| {
@@ -1007,6 +996,10 @@ fn normalize_dns_values(values: impl IntoIterator- ) -> Vec
values
}
+fn dns_state_matches_target(state: &PublishedDnsRecordState, zone_id: &str, fqdn: &str) -> bool {
+ state.zone_id == zone_id && state.fqdn == fqdn
+}
+
fn desired_dns_values(
spec: &DnsPublicationSpec,
healthy_instances: &[ServiceInstanceSpec],
@@ -1324,6 +1317,32 @@ mod tests {
);
}
+ #[test]
+ fn test_dns_state_match_requires_same_zone_and_fqdn() {
+ let state = PublishedDnsRecordState {
+ zone_id: "zone-1".to_string(),
+ record_ids: vec!["record-1".to_string()],
+ fqdn: "api.native.cluster.test".to_string(),
+ values: vec!["10.0.0.11".to_string()],
+ };
+
+ assert!(dns_state_matches_target(
+ &state,
+ "zone-1",
+ "api.native.cluster.test"
+ ));
+ assert!(!dns_state_matches_target(
+ &state,
+ "zone-2",
+ "api.native.cluster.test"
+ ));
+ assert!(!dns_state_matches_target(
+ &state,
+ "zone-1",
+ "web.native.cluster.test"
+ ));
+ }
+
#[test]
fn test_publishable_instance_requires_fresh_heartbeat() {
let now = Utc::now();
diff --git a/flashdns/crates/flashdns-server/src/metadata.rs b/flashdns/crates/flashdns-server/src/metadata.rs
index fb9eff3..d96405e 100644
--- a/flashdns/crates/flashdns-server/src/metadata.rs
+++ b/flashdns/crates/flashdns-server/src/metadata.rs
@@ -413,20 +413,6 @@ impl DnsMetadataStore {
format!("/flashdns/records/{}/", zone_id)
}
- fn record_type_prefix(zone_id: &ZoneId, record_name: &str, record_type: RecordType) -> String {
- format!(
- "/flashdns/records/{}/{}/{}/",
- zone_id, record_name, record_type
- )
- }
-
- fn legacy_record_key(zone_id: &ZoneId, record_name: &str, record_type: RecordType) -> String {
- format!(
- "/flashdns/records/{}/{}/{}",
- zone_id, record_name, record_type
- )
- }
-
fn record_id_key(record_id: &RecordId) -> String {
format!("/flashdns/record_ids/{}", record_id)
}
@@ -566,37 +552,6 @@ impl DnsMetadataStore {
Ok(())
}
- /// Load the first record by name and type, preserving compatibility with
- /// older single-record keys.
- pub async fn load_record(
- &self,
- zone_id: &ZoneId,
- record_name: &str,
- record_type: RecordType,
- ) -> Result