Skip to content

Commit 58255a3

Browse files
committed
MGMT-21985: Enable primary IPv6 clusters.
Background: There are two variants of dual-stack clusters: * IPv4 primary, IPv6 secondary * IPv6 primary, IPv4 secondary Only the first variant was supported until now, This PR enables the second variant as well by removing all assumptions about the order of which the ips are provided / detected.
1 parent 9d60bef commit 58255a3

File tree

3 files changed

+25
-61
lines changed

3 files changed

+25
-61
lines changed

hack/dummy_config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ extend_expiration: true
3030
force_expire: false
3131
hostname: test.hostname
3232
ip:
33-
- 192.168.126.99
3433
- 2001:db8::99
34+
- 192.168.126.99
3535
# proxy: http://registry.kni-qe-0.lab.eng.rdu2.redhat.com:3128|http://registry.kni-qe-0.lab.eng.rdu2.redhat.com:3130|.cluster.local,.kni-qe-2.lab.eng.rdu2.redhat.com,.svc,127.0.0.1,2620:52:0:11c::/64,2620:52:0:11c::1,2620:52:0:11c::10,2620:52:0:11c::11,2620:52:0:199::/64,api-int.kni-qe-2.lab.eng.rdu2.redhat.com,fd01::/48,fd02::/112,localhost|http://registry.kni-qe-0.lab.eng.rdu2.redhat.com:3128|http://registry.kni-qe-0.lab.eng.rdu2.redhat.com:3130|.cluster.local,.kni-qe-2.lab.eng.rdu2.redhat.com,.svc,127.0.0.1,2620:52:0:11c::/64,2620:52:0:11c::1,2620:52:0:11c::10,2620:52:0:11c::11,2620:52:0:199::/64,api-int.kni-qe-2.lab.eng.rdu2.redhat.com,fd01::/48,fd02::/112,localhost,moreproxy
3636
install_config: |
3737
additionalTrustBundlePolicy: Proxyonly

src/ocp_postprocess/ip_rename.rs

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ pub(crate) async fn rename_all_dual_stack(
2525
.await
2626
.context("extracting original dual-stack IPs")?;
2727

28+
ensure!(
29+
original_ips.len() == ips.len(),
30+
"original IPs count ({}) must equal new IPs count ({})",
31+
original_ips.len(),
32+
ips.len()
33+
);
34+
35+
log::info!("Applying dual-stack IP changes");
36+
2837
fix_etcd_resources_dual_stack(etcd_client, &original_ips, ips)
2938
.await
3039
.context("modifying etcd resources for dual stack")?;
@@ -73,15 +82,11 @@ async fn fix_dir_resources(original_ip: &str, ip: &str, dir: &Path) -> Result<()
7382
}
7483

7584
async fn fix_dir_resources_dual_stack(original_ips: &[String], ips: &[String], dir: &Path) -> Result<()> {
76-
// Apply IPv4 replacement (original IPv4 → new IPv4)
77-
filesystem_rename::fix_filesystem_ip(&original_ips[0], &ips[0], dir)
78-
.await
79-
.context(format!("fix filesystem IPv4 in {:?}", dir))?;
80-
81-
// Apply IPv6 replacement (original IPv6 → new IPv6) - both are guaranteed to be present
82-
filesystem_rename::fix_filesystem_ip(&original_ips[1], &ips[1], dir)
83-
.await
84-
.context(format!("fix filesystem IPv6 in {:?}", dir))?;
85+
for (idx, (original_ip, new_ip)) in original_ips.iter().zip(ips.iter()).enumerate() {
86+
filesystem_rename::fix_filesystem_ip(original_ip, new_ip, dir)
87+
.await
88+
.context(format!("fix filesystem IP replacement pair {} in {:?}", idx, dir))?;
89+
}
8590

8691
Ok(())
8792
}
@@ -181,31 +186,12 @@ async fn extract_original_dual_stack_ips(etcd_client: &Arc<InMemoryK8sEtcd>) ->
181186
}
182187

183188
async fn fix_etcd_resources_dual_stack(etcd_client: &Arc<InMemoryK8sEtcd>, original_ips: &[String], new_ips: &[String]) -> Result<()> {
184-
let original_ipv4 = &original_ips[0];
185-
let original_ipv6 = &original_ips[1];
186-
187-
let new_ipv4 = &new_ips[0];
188-
let new_ipv6 = new_ips.get(1).context("Second IP (IPv6) is required for dual-stack processing")?;
189-
190-
log::info!(
191-
"Applying dual-stack IP changes - IPv4: {} → {}, IPv6: {} → {}",
192-
original_ipv4,
193-
new_ipv4,
194-
original_ipv6,
195-
new_ipv6
196-
);
197-
198-
log::info!("Applying IPv4 replacements: {} → {}", original_ipv4, new_ipv4);
199-
200-
fix_etcd_resources_for_ip_pair(etcd_client, original_ipv4, new_ipv4)
201-
.await
202-
.context("applying IPv4 etcd resource fixes")?;
203-
204-
log::info!("Applying IPv6 replacements: {} → {}", original_ipv6, new_ipv6);
205-
206-
fix_etcd_resources_for_ip_pair(etcd_client, original_ipv6, new_ipv6)
207-
.await
208-
.context("applying IPv6 etcd resource fixes")?;
189+
for (idx, (original_ip, new_ip)) in original_ips.iter().zip(new_ips.iter()).enumerate() {
190+
log::info!("Applying replacements pair {}: {} → {}", idx, original_ip, new_ip);
191+
fix_etcd_resources_for_ip_pair(etcd_client, original_ip, new_ip)
192+
.await
193+
.context(format!("applying etcd resource fixes for pair {}", idx))?;
194+
}
209195

210196
Ok(())
211197
}

src/ocp_postprocess/ip_rename/etcd_rename.rs

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,9 @@ use crate::{
66
use anyhow::{bail, ensure, Context, Result};
77
use futures_util::future::join_all;
88
use serde_json::Value;
9-
use std::net::{IpAddr, Ipv6Addr};
9+
use std::net::Ipv6Addr;
1010
use std::sync::Arc;
1111

12-
fn is_ipv6(ip: &str) -> Result<bool> {
13-
let addr = ip
14-
.parse::<IpAddr>()
15-
.with_context(|| format!("Failed to parse IP address: {}", ip))?;
16-
Ok(addr.is_ipv6())
17-
}
18-
1912
// Extract both original IPv4 and IPv6 IPs from dual-stack cluster node configuration
2013
pub(crate) async fn extract_original_ips(etcd_client: &Arc<InMemoryK8sEtcd>) -> Result<Vec<String>> {
2114
// Extract IPs from node addresses - works for both single-stack and dual-stack
@@ -43,40 +36,25 @@ async fn extract_original_ips_from_nodes(etcd_client: &Arc<InMemoryK8sEtcd>) ->
4336
.and_then(|a| a.as_array())
4437
.context("Node does not have /status/addresses array")?;
4538

46-
let mut original_ipv4: Option<String> = None;
47-
let mut original_ipv6: Option<String> = None;
39+
let mut result = Vec::new();
4840

4941
for address in addresses {
5042
if let (Some(addr_type), Some(addr_value)) = (
5143
address.pointer("/type").and_then(|t| t.as_str()),
5244
address.pointer("/address").and_then(|a| a.as_str()),
5345
) {
5446
if addr_type == "InternalIP" {
55-
if is_ipv6(addr_value)? {
56-
original_ipv6 = Some(addr_value.to_string());
57-
} else {
58-
original_ipv4 = Some(addr_value.to_string());
59-
}
47+
result.push(addr_value.to_string());
6048
}
6149
}
6250
}
6351

64-
let mut result = Vec::new();
65-
66-
if let Some(ipv4) = original_ipv4 {
67-
result.push(ipv4);
68-
}
69-
70-
if let Some(ipv6) = original_ipv6 {
71-
result.push(ipv6);
72-
}
73-
7452
ensure!(!result.is_empty(), "No InternalIP addresses found in node configuration");
7553

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

8260
Ok(result)

0 commit comments

Comments
 (0)