Skip to content

Commit 826b003

Browse files
committed
MGMT-22237: Implement the required changes for IP Configuration flow: IP configuration is a new flow which will be introduced soon in LCA. The flow essentialy performs IP change in SNO clusters. To perform the change correctly, we need to change the IP in the pods statuses as well and delete the old node for regenration. IBU doesn't require this logic because it changes the hostname and in that case recert deletes the pods and node anyway.
1 parent bc89231 commit 826b003

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

src/etcd_encoding.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::protobuf_gen::{
55
admissionregistration::v1::{MutatingWebhookConfiguration, ValidatingWebhookConfiguration},
66
apps::v1::{ControllerRevision, DaemonSet, Deployment, StatefulSet},
77
batch::v1::{CronJob, Job},
8-
core::v1::{ConfigMap, Node, Secret},
8+
core::v1::{ConfigMap, Node, Pod, Secret},
99
},
1010
apimachinery::pkg::runtime::{TypeMeta, Unknown},
1111
},
@@ -58,6 +58,7 @@ k8s_type!(StatefulSetWithMeta, StatefulSet);
5858
k8s_type!(ConfigMapWithMeta, ConfigMap);
5959
k8s_type!(NodeWithMeta, Node);
6060
k8s_type!(SecretWithMeta, Secret);
61+
k8s_type!(PodWithMeta, Pod);
6162
k8s_type!(ValidatingWebhookConfigurationWithMeta, ValidatingWebhookConfiguration);
6263
k8s_type!(MutatingWebhookConfigurationWithMeta, MutatingWebhookConfiguration);
6364
k8s_type!(OAuthClientWithMeta, OAuthClient);
@@ -89,6 +90,7 @@ pub(crate) async fn decode(data: &[u8]) -> Result<Vec<u8>> {
8990
"ConfigMap" => serde_json::to_vec(&ConfigMapWithMeta::try_from(unknown)?)?,
9091
"Node" => serde_json::to_vec(&NodeWithMeta::try_from(unknown)?)?,
9192
"Secret" => serde_json::to_vec(&SecretWithMeta::try_from(unknown)?)?,
93+
"Pod" => serde_json::to_vec(&PodWithMeta::try_from(unknown)?)?,
9294
"ValidatingWebhookConfiguration" => serde_json::to_vec(&ValidatingWebhookConfigurationWithMeta::try_from(unknown)?)?,
9395
"MutatingWebhookConfiguration" => serde_json::to_vec(&MutatingWebhookConfigurationWithMeta::try_from(unknown)?)?,
9496
"OAuthClient" => serde_json::to_vec(&OAuthClientWithMeta::try_from(unknown)?)?,
@@ -111,6 +113,8 @@ pub(crate) async fn encode(data: &[u8]) -> Result<Vec<u8>> {
111113
"ConfigMap" => Unknown::from(serde_json::from_slice::<ConfigMapWithMeta>(data)?),
112114
"Route" => Unknown::from(serde_json::from_slice::<RouteWithMeta>(data)?),
113115
"Secret" => Unknown::from(serde_json::from_slice::<SecretWithMeta>(data)?),
116+
"Node" => Unknown::from(serde_json::from_slice::<NodeWithMeta>(data)?),
117+
"Pod" => Unknown::from(serde_json::from_slice::<PodWithMeta>(data)?),
114118
"Deployment" => Unknown::from(serde_json::from_slice::<DeploymentWithMeta>(data)?),
115119
"ControllerRevision" => Unknown::from(serde_json::from_slice::<ControllerRevisionWithMeta>(data)?),
116120
"Job" => Unknown::from(serde_json::from_slice::<JobWithMeta>(data)?),

src/ocp_postprocess/ip_rename.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ async fn fix_etcd_resources_for_ip_pair(etcd_client: &Arc<InMemoryK8sEtcd>, orig
149149
.await
150150
.context("fixing etcd member")?;
151151

152+
etcd_rename::fix_pods_status(etcd_client, original_ip, new_ip)
153+
.await
154+
.context("fixing pods status")?;
155+
156+
etcd_rename::delete_minions_if_exist(etcd_client)
157+
.await
158+
.context("deleting minions if exist")?;
159+
152160
Ok(())
153161
}
154162

src/ocp_postprocess/ip_rename/etcd_rename.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,108 @@ pub(crate) async fn fix_etcd_member(etcd_client: &Arc<InMemoryK8sEtcd>, original
597597
Ok(())
598598
}
599599

600+
pub(crate) async fn fix_pods_status(etcd_client: &Arc<InMemoryK8sEtcd>, original_ip: &str, ip: &str) -> Result<()> {
601+
// Only mutate known Pod status IP fields if they equal the original IP
602+
fn replace_status_ips(pod: &mut Value, original_ip: &str, new_ip: &str) -> Result<bool> {
603+
let mut changed = false;
604+
605+
// status.podIP
606+
if let Some(v) = pod.pointer_mut("/status/podIP") {
607+
if let Some(curr) = v.as_str() {
608+
if curr == original_ip {
609+
*v = Value::String(new_ip.to_string());
610+
changed = true;
611+
}
612+
}
613+
}
614+
615+
// status.hostIP
616+
if let Some(v) = pod.pointer_mut("/status/hostIP") {
617+
if let Some(curr) = v.as_str() {
618+
if curr == original_ip {
619+
*v = Value::String(new_ip.to_string());
620+
changed = true;
621+
}
622+
}
623+
}
624+
625+
// status.podIPs (array of objects {ip: string} or strings)
626+
if let Some(arr) = pod.pointer_mut("/status/podIPs").and_then(|v| v.as_array_mut()) {
627+
for entry in arr.iter_mut() {
628+
if let Some(s) = entry.as_str() {
629+
if s == original_ip {
630+
*entry = Value::String(new_ip.to_string());
631+
changed = true;
632+
}
633+
continue;
634+
}
635+
if let Some(ip_field) = entry.as_object_mut().and_then(|m| m.get_mut("ip")) {
636+
if let Some(s) = ip_field.as_str() {
637+
if s == original_ip {
638+
*ip_field = Value::String(new_ip.to_string());
639+
changed = true;
640+
}
641+
}
642+
}
643+
}
644+
}
645+
646+
// status.hostIPs (array of objects {ip: string} or strings) - if present
647+
if let Some(arr) = pod.pointer_mut("/status/hostIPs").and_then(|v| v.as_array_mut()) {
648+
for entry in arr.iter_mut() {
649+
if let Some(s) = entry.as_str() {
650+
if s == original_ip {
651+
*entry = Value::String(new_ip.to_string());
652+
changed = true;
653+
}
654+
continue;
655+
}
656+
if let Some(ip_field) = entry.as_object_mut().and_then(|m| m.get_mut("ip")) {
657+
if let Some(s) = ip_field.as_str() {
658+
if s == original_ip {
659+
*ip_field = Value::String(new_ip.to_string());
660+
changed = true;
661+
}
662+
}
663+
}
664+
}
665+
}
666+
667+
Ok(changed)
668+
}
669+
670+
join_all(etcd_client.list_keys("pods/").await?.into_iter().map(|key| async move {
671+
let etcd_result = etcd_client
672+
.get(key.clone())
673+
.await
674+
.with_context(|| format!("getting key {:?}", key))?
675+
.context("key disappeared")?;
676+
let value: Value =
677+
serde_yaml::from_slice(etcd_result.value.as_slice()).with_context(|| format!("deserializing value of key {:?}", key,))?;
678+
let k8s_resource_location = K8sResourceLocation::try_from(&value)?;
679+
680+
let mut pod = get_etcd_json(etcd_client, &k8s_resource_location).await?.context("getting pod")?;
681+
682+
if replace_status_ips(&mut pod, original_ip, ip)? {
683+
put_etcd_yaml(etcd_client, &k8s_resource_location, pod).await?;
684+
}
685+
686+
Ok(())
687+
}))
688+
.await
689+
.into_iter()
690+
.collect::<Result<Vec<_>>>()?;
691+
692+
Ok(())
693+
}
694+
695+
pub(crate) async fn delete_minions_if_exist(etcd_client: &Arc<InMemoryK8sEtcd>) -> Result<()> {
696+
for key in etcd_client.list_keys("minions").await? {
697+
etcd_client.delete(&key).await.context(format!("deleting {}", key))?;
698+
}
699+
Ok(())
700+
}
701+
600702
fn replace_etcd_servers(cluster: &mut Value, original_ip: &str, ip: &str) -> Result<()> {
601703
let observed_config = cluster.pointer_mut("/spec/observedConfig").context("no /spec/observedConfig")?;
602704

src/ocp_postprocess/ip_rename/filesystem_rename.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub(crate) async fn fix_filesystem_ip(original_ip: &str, ip: &str, dir: &Path) -
1111
file_utils::globvec(dir, "**/etcd-pod.yaml")?
1212
.into_iter()
1313
.chain(file_utils::globvec(dir, "**/*etcd-pod/pod.yaml")?)
14+
.chain(file_utils::globvec(dir, "**/restore-etcd-pod/quorum-restore-pod.yaml")?)
1415
.chain(file_utils::globvec(dir, "**/etcd-scripts/etcd.env")?)
1516
.chain(file_utils::globvec(dir, "**/etcd-endpoints/*")?)
1617
.chain(file_utils::globvec(dir, "**/kube-apiserver-pod-*/configmaps/config/config.yaml")?)

0 commit comments

Comments
 (0)