Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 20 additions & 34 deletions src/ocp_postprocess/ip_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ pub(crate) async fn rename_all_dual_stack(
.await
.context("extracting original dual-stack IPs")?;

ensure!(
original_ips.len() == ips.len(),
"original IPs count ({}) must equal new IPs count ({})",
original_ips.len(),
ips.len()
);

log::info!("Applying dual-stack IP changes");

fix_etcd_resources_dual_stack(etcd_client, &original_ips, ips)
.await
.context("modifying etcd resources for dual stack")?;
Expand Down Expand Up @@ -73,15 +82,11 @@ async fn fix_dir_resources(original_ip: &str, ip: &str, dir: &Path) -> Result<()
}

async fn fix_dir_resources_dual_stack(original_ips: &[String], ips: &[String], dir: &Path) -> Result<()> {
// Apply IPv4 replacement (original IPv4 → new IPv4)
filesystem_rename::fix_filesystem_ip(&original_ips[0], &ips[0], dir)
.await
.context(format!("fix filesystem IPv4 in {:?}", dir))?;

// Apply IPv6 replacement (original IPv6 → new IPv6) - both are guaranteed to be present
filesystem_rename::fix_filesystem_ip(&original_ips[1], &ips[1], dir)
.await
.context(format!("fix filesystem IPv6 in {:?}", dir))?;
for (idx, (original_ip, new_ip)) in original_ips.iter().zip(ips.iter()).enumerate() {
filesystem_rename::fix_filesystem_ip(original_ip, new_ip, dir)
.await
.context(format!("fix filesystem IP replacement pair {} in {:?}", idx, dir))?;
}

Ok(())
}
Expand Down Expand Up @@ -181,31 +186,12 @@ async fn extract_original_dual_stack_ips(etcd_client: &Arc<InMemoryK8sEtcd>) ->
}

async fn fix_etcd_resources_dual_stack(etcd_client: &Arc<InMemoryK8sEtcd>, original_ips: &[String], new_ips: &[String]) -> Result<()> {
let original_ipv4 = &original_ips[0];
let original_ipv6 = &original_ips[1];

let new_ipv4 = &new_ips[0];
let new_ipv6 = new_ips.get(1).context("Second IP (IPv6) is required for dual-stack processing")?;

log::info!(
"Applying dual-stack IP changes - IPv4: {} → {}, IPv6: {} → {}",
original_ipv4,
new_ipv4,
original_ipv6,
new_ipv6
);

log::info!("Applying IPv4 replacements: {} → {}", original_ipv4, new_ipv4);

fix_etcd_resources_for_ip_pair(etcd_client, original_ipv4, new_ipv4)
.await
.context("applying IPv4 etcd resource fixes")?;

log::info!("Applying IPv6 replacements: {} → {}", original_ipv6, new_ipv6);

fix_etcd_resources_for_ip_pair(etcd_client, original_ipv6, new_ipv6)
.await
.context("applying IPv6 etcd resource fixes")?;
for (idx, (original_ip, new_ip)) in original_ips.iter().zip(new_ips.iter()).enumerate() {
log::info!("Applying replacements pair {}: {} → {}", idx, original_ip, new_ip);
fix_etcd_resources_for_ip_pair(etcd_client, original_ip, new_ip)
.await
.context(format!("applying etcd resource fixes for pair {}", idx))?;
}

Ok(())
}
30 changes: 4 additions & 26 deletions src/ocp_postprocess/ip_rename/etcd_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,9 @@ use crate::{
use anyhow::{bail, ensure, Context, Result};
use futures_util::future::join_all;
use serde_json::Value;
use std::net::{IpAddr, Ipv6Addr};
use std::net::Ipv6Addr;
use std::sync::Arc;

fn is_ipv6(ip: &str) -> Result<bool> {
let addr = ip
.parse::<IpAddr>()
.with_context(|| format!("Failed to parse IP address: {}", ip))?;
Ok(addr.is_ipv6())
}

// Extract both original IPv4 and IPv6 IPs from dual-stack cluster node configuration
pub(crate) async fn extract_original_ips(etcd_client: &Arc<InMemoryK8sEtcd>) -> Result<Vec<String>> {
// Extract IPs from node addresses - works for both single-stack and dual-stack
Expand Down Expand Up @@ -43,40 +36,25 @@ async fn extract_original_ips_from_nodes(etcd_client: &Arc<InMemoryK8sEtcd>) ->
.and_then(|a| a.as_array())
.context("Node does not have /status/addresses array")?;

let mut original_ipv4: Option<String> = None;
let mut original_ipv6: Option<String> = None;
let mut result = Vec::new();

for address in addresses {
if let (Some(addr_type), Some(addr_value)) = (
address.pointer("/type").and_then(|t| t.as_str()),
address.pointer("/address").and_then(|a| a.as_str()),
) {
if addr_type == "InternalIP" {
if is_ipv6(addr_value)? {
original_ipv6 = Some(addr_value.to_string());
} else {
original_ipv4 = Some(addr_value.to_string());
}
result.push(addr_value.to_string());
}
}
}

let mut result = Vec::new();

if let Some(ipv4) = original_ipv4 {
result.push(ipv4);
}

if let Some(ipv6) = original_ipv6 {
result.push(ipv6);
}

ensure!(!result.is_empty(), "No InternalIP addresses found in node configuration");

if result.len() == 1 {
log::info!("Found single-stack IP: {}", result[0]);
} else {
log::info!("Found dual-stack IPs - IPv4: {}, IPv6: {}", result[0], result[1]);
log::info!("Found {} InternalIP(s) {}", result.len(), result.join(", "));
}

Ok(result)
Expand Down