diff --git a/k8s/upgrade/src/common/constants.rs b/k8s/upgrade/src/common/constants.rs index 518cf58e7..03ad87101 100644 --- a/k8s/upgrade/src/common/constants.rs +++ b/k8s/upgrade/src/common/constants.rs @@ -56,4 +56,7 @@ pub(crate) const TWO_DOT_FIVE: &str = "2.5.0"; pub(crate) const TWO_DOT_SIX: &str = "2.6.0"; /// Version value for 2.7.2 release. -pub(crate) const TWO_DOT_SEVENT_DOT_TWO: &str = "2.7.2"; +pub(crate) const TWO_DOT_SEVEN_DOT_TWO: &str = "2.7.2"; + +/// Version value for 2.7.3. +pub(crate) const TWO_DOT_SEVEN_DOT_THREE: &str = "2.7.3"; diff --git a/k8s/upgrade/src/common/error.rs b/k8s/upgrade/src/common/error.rs index ff771c0a9..4d7381e39 100644 --- a/k8s/upgrade/src/common/error.rs +++ b/k8s/upgrade/src/common/error.rs @@ -485,6 +485,47 @@ pub enum Error { object: String, }, + /// Error in serializing base.initContainers.containers. + #[snafu(display("Failed to serialize .base.initContainers.containers {object:?}: {source}",))] + SerializeBaseInitContainersToJson { + source: serde_json::Error, + object: Container, + }, + + /// Error in serializing base.initCoreContainers.containers. + #[snafu(display( + "Failed to serialize .base.initCoreContainers.containers {object:?}: {source}", + ))] + SerializeBaseInitCoreContainersToJson { + source: serde_json::Error, + object: Container, + }, + + /// Error in serializing base.initHaNodeContainers.containers. + #[snafu(display( + "Failed to serialize .base.initHaNodeContainers.containers {object:?}: {source}", + ))] + SerializeBaseInitHaNodeContainersToJson { + source: serde_json::Error, + object: Container, + }, + + /// Error in serializing base.initRestContainer.initContainer. + #[snafu(display( + "Failed to serialize .base.initRestContainer.initContainer {object:?}: {source}", + ))] + SerializeBaseInitRestContainerToJson { + source: serde_json::Error, + object: Container, + }, + + /// Error in serializing base.jaeger.agent.initContainers. + #[snafu(display("Failed to serialize .base.jaeger.agent.initContainer {object:?}: {source}",))] + SerializeJaegerAgentInitContainerToJson { + source: serde_json::Error, + object: Container, + }, + /// Error for when there are too many io-engine Pods in one single node; #[snafu(display("Too many io-engine Pods in Node '{node_name}'"))] TooManyIoEnginePods { node_name: String }, diff --git a/k8s/upgrade/src/helm/chart.rs b/k8s/upgrade/src/helm/chart.rs index 127314c03..af0520e7b 100644 --- a/k8s/upgrade/src/helm/chart.rs +++ b/k8s/upgrade/src/helm/chart.rs @@ -259,11 +259,6 @@ impl CoreValues { self.loki_stack.grafana_sidecar_image_tag() } - /// This is a getter for the localpv-provisioner sub-chart's release version. - pub(crate) fn localpv_release_version(&self) -> &str { - self.localpv_provisioner.release_version() - } - /// This is a getter for the container image tag of the hostpath localpv provisioner. pub(crate) fn localpv_provisioner_image_tag(&self) -> &str { self.localpv_provisioner.provisioner_image_tag() @@ -299,6 +294,31 @@ impl CoreValues { self.base.deprecated_log_silence_level() } + /// This is the array of containers associated with core initContainers. + pub(crate) fn base_init_core_containers(&self) -> &[Container] { + self.base.init_core_containers() + } + + /// This is the array of containers associated with ha node initContainers. + pub(crate) fn base_init_ha_node_containers(&self) -> &[Container] { + self.base.init_ha_node_containers() + } + + /// This is the array of containers associated with rest api initContainer. + pub(crate) fn base_init_rest_container(&self) -> &[Container] { + self.base.init_rest_container() + } + + /// This is the array of containers associated with default initContainers. + pub(crate) fn base_init_containers(&self) -> &[Container] { + self.base.init_containers() + } + + /// This is the array of containers associated with jaeger agent initContainers. + pub(crate) fn base_jaeger_agent_init_container(&self) -> &[Container] { + self.base.jaeger_agent_init_container() + } + /// Retrieves the image tag of the Jaeger operator. /// Useful when updating the Jaeger operator dependency chart to ensure the new chart uses the /// updated image tag. @@ -328,10 +348,16 @@ impl Agents { /// This is used to deserialize the yaml object base. #[derive(Deserialize)] +#[serde(rename_all(deserialize = "camelCase"))] struct Base { /// This is the older helm value.yaml key for configuring log silence level. #[serde(default, rename(deserialize = "logSilenceLevel"))] deprecated_log_silence_level: String, + init_containers: GenericContainers, + init_core_containers: GenericContainers, + init_ha_node_containers: GenericContainers, + init_rest_container: InitRestContainer, + jaeger: Jaeger, } impl Base { @@ -339,6 +365,58 @@ impl Base { fn deprecated_log_silence_level(&self) -> &str { self.deprecated_log_silence_level.as_str() } + + /// This returns the array of kubernetes initContainer objects. + fn init_containers(&self) -> &[Container] { + self.init_containers.containers() + } + + /// This returns the array of kubernetes initContainer objects for core. + fn init_core_containers(&self) -> &[Container] { + self.init_core_containers.containers() + } + + /// This returns the array of kubernetes initContainer objects for ha node. + fn init_ha_node_containers(&self) -> &[Container] { + self.init_ha_node_containers.containers() + } + + /// This returns the array of kubernetes initContainer objects for rest. + fn init_rest_container(&self) -> &[Container] { + self.init_rest_container.init_container() + } + + /// This returns the array of kubernetes initContainer objects for jaeger agent. + fn jaeger_agent_init_container(&self) -> &[Container] { + self.jaeger.agent_init_container() + } +} + +/// This is used to deserialize the .base.initRestContainer object. +#[derive(Deserialize)] +#[serde(rename_all(deserialize = "camelCase"))] +struct InitRestContainer { + init_container: Vec, +} + +impl InitRestContainer { + fn init_container(&self) -> &[Container] { + self.init_container.as_slice() + } +} + +/// This is used to deserialize various 'containers' yaml objects. +#[derive(Deserialize)] +struct GenericContainers { + /// Container config. + containers: Vec, +} + +impl GenericContainers { + /// Returns container config. + fn containers(&self) -> &[Container] { + self.containers.as_slice() + } } /// This is used to deserialize the yaml object 'agents.core'. @@ -1063,17 +1141,11 @@ impl PromtailConfigClient { #[derive(Default, Deserialize)] #[serde(default, rename_all(deserialize = "camelCase"))] struct LocalpvProvisioner { - release: LocalpvProvisionerRelease, localpv: LocalpvProvisionerLocalpv, helper_pod: LocalpvProvisionerHelperPod, } impl LocalpvProvisioner { - /// This is a getter for the localpv-provisioner helm chart's release version. - fn release_version(&self) -> &str { - self.release.version() - } - /// This is a getter for the container image tag of the provisioner-localpv container. fn provisioner_image_tag(&self) -> &str { self.localpv.image_tag() @@ -1085,22 +1157,6 @@ impl LocalpvProvisioner { } } -/// This is used to deserialize the 'release.version' yaml object in the localpv-provisioner helm -/// chart. -#[derive(Default, Deserialize)] -struct LocalpvProvisionerRelease { - #[serde(default)] - version: String, -} - -impl LocalpvProvisionerRelease { - /// This is a getter for the release version for the localpv-provisioner helm chart. - /// This value is set as the value of the 'openebs.io/version' label. - fn version(&self) -> &str { - self.version.as_str() - } -} - /// This is used to deserialize the 'localpv' yaml object in the localpv-provisioner helm chart. #[derive(Default, Deserialize)] struct LocalpvProvisionerLocalpv { @@ -1144,6 +1200,33 @@ impl LocalpvProvisionerHelperPod { } } +/// This is used to deserialize the '.jaeger' yaml object. +#[derive(Deserialize)] +struct Jaeger { + agent: JaegerAgent, +} + +impl Jaeger { + /// This returns the init containers from the base jaeger agent. + fn agent_init_container(&self) -> &[Container] { + self.agent.init_container() + } +} + +/// This is used to deserialize the '.jaeger.agent' yaml object. +#[derive(Deserialize)] +#[serde(rename_all(deserialize = "camelCase"))] +struct JaegerAgent { + init_container: Vec, +} + +impl JaegerAgent { + /// This returns the init containers from the base jaeger agent. + fn init_container(&self) -> &[Container] { + self.init_container.as_slice() + } +} + /// This is used to deserialize the '.jaeger-operator' yaml object. #[derive(Default, Deserialize)] struct JaegerOperator { diff --git a/k8s/upgrade/src/helm/values.rs b/k8s/upgrade/src/helm/values.rs index 0bd3ce731..083effc5b 100644 --- a/k8s/upgrade/src/helm/values.rs +++ b/k8s/upgrade/src/helm/values.rs @@ -2,12 +2,14 @@ use crate::{ common::{ constants::{ KUBE_API_PAGE_SIZE, TWO_DOT_FIVE, TWO_DOT_FOUR, TWO_DOT_ONE, TWO_DOT_O_RC_ONE, - TWO_DOT_SEVENT_DOT_TWO, TWO_DOT_SIX, TWO_DOT_THREE, + TWO_DOT_SEVEN_DOT_THREE, TWO_DOT_SEVEN_DOT_TWO, TWO_DOT_SIX, TWO_DOT_THREE, }, error::{ DeserializePromtailExtraConfig, ListCrds, Result, SemverParse, - SerializePromtailConfigClientToJson, SerializePromtailExtraConfigToJson, - SerializePromtailInitContainerToJson, + SerializeBaseInitContainersToJson, SerializeBaseInitCoreContainersToJson, + SerializeBaseInitHaNodeContainersToJson, SerializeBaseInitRestContainerToJson, + SerializeJaegerAgentInitContainerToJson, SerializePromtailConfigClientToJson, + SerializePromtailExtraConfigToJson, SerializePromtailInitContainerToJson, }, file::write_to_tempfile, kube::client as KubeClient, @@ -218,35 +220,20 @@ where version_string: TWO_DOT_SIX.to_string(), })?; if source_version.ge(&two_dot_o_rc_zero) && source_version.lt(&two_dot_six) { - // Update localpv-provisioner helm chart. - // This change is meant for versions from 2.0.0 to 2.4.0. However, this code wasn't checked - // into 2.5.0, and likely users of upgrade-job 2.5.0 are using the localpv image tag - // from 2.4.0 (i.e. 3.4.0) with the 3.5.0 localpv helm chart. So these options should - // also be set for source version 2.5.0. - let localpv_version_to_replace = "3.4.0"; - if source_values - .localpv_release_version() - .eq(localpv_version_to_replace) - && target_values - .localpv_release_version() - .ne(localpv_version_to_replace) - { - yq.set_literal_value( - YamlKey::try_from(".localpv-provisioner.release.version")?, - target_values.localpv_release_version(), - upgrade_values_file.path(), - )?; - yq.set_literal_value( - YamlKey::try_from(".localpv-provisioner.localpv.image.tag")?, - target_values.localpv_provisioner_image_tag(), - upgrade_values_file.path(), - )?; - yq.set_literal_value( - YamlKey::try_from(".localpv-provisioner.helperPod.image.tag")?, - target_values.localpv_helper_image_tag(), - upgrade_values_file.path(), - )?; - } + // LocalPV Device mode was removed in OpenEBS/Dynamic LocalPV v4.0.0. + // Mayastor 2.6 uses Dynamic LocalPV v4.0.0 as a dependency. + yq.delete_object( + YamlKey::try_from(".localpv-provisioner.deviceClass")?, + upgrade_values_file.path(), + )?; + yq.delete_object( + YamlKey::try_from(".localpv-provisioner.localpv.waitForBDBindTimeoutRetryCount")?, + upgrade_values_file.path(), + )?; + yq.delete_object( + YamlKey::try_from(".localpv-provisioner.openebsNDM")?, + upgrade_values_file.path(), + )?; // Switch out image tag for the latest one. yq.set_literal_value( @@ -373,14 +360,166 @@ where } // Special-case values for 2.7.2. - let two_dot_seven_dot_two = Version::parse(TWO_DOT_SEVENT_DOT_TWO).context(SemverParse { - version_string: TWO_DOT_SEVENT_DOT_TWO.to_string(), + let two_dot_seven_dot_two = Version::parse(TWO_DOT_SEVEN_DOT_TWO).context(SemverParse { + version_string: TWO_DOT_SEVEN_DOT_TWO.to_string(), })?; if source_version.ge(&two_dot_o_rc_zero) && source_version.lt(&two_dot_seven_dot_two) { yq.delete_object( YamlKey::try_from(".localpv-provisioner.release")?, upgrade_values_file.path(), )?; + + let image_tag_to_remove = String::from("busybox:latest"); + // if base.initContainers.containers elements contain the image key + if source_values + .base_init_containers() + .iter() + .filter_map(|container| container.image.clone()) + .collect::>() + .contains(&image_tag_to_remove) + { + let init_containers_key = YamlKey::try_from(".base.initContainers.containers")?; + + yq.delete_object(init_containers_key.clone(), upgrade_values_file.path())?; + + for container in target_values.base_init_containers() { + let container_val = serde_json::to_string(container).context( + SerializeBaseInitContainersToJson { + object: container.clone(), + }, + )?; + yq.append_to_array( + init_containers_key.clone(), + container_val, + upgrade_values_file.path(), + )?; + } + } + + // if base.initCoreContainers.containers elements contain the image key + if source_values + .base_init_core_containers() + .iter() + .filter_map(|container| container.image.clone()) + .collect::>() + .contains(&image_tag_to_remove) + { + let init_core_containers_key = + YamlKey::try_from(".base.initCoreContainers.containers")?; + + yq.delete_object(init_core_containers_key.clone(), upgrade_values_file.path())?; + + for container in target_values.base_init_core_containers() { + let container_val = serde_json::to_string(container).context( + SerializeBaseInitCoreContainersToJson { + object: container.clone(), + }, + )?; + yq.append_to_array( + init_core_containers_key.clone(), + container_val, + upgrade_values_file.path(), + )?; + } + } + + // if base.initHaNodeContainers.containers elements contain the image key + if source_values + .base_init_ha_node_containers() + .iter() + .filter_map(|container| container.image.clone()) + .collect::>() + .contains(&image_tag_to_remove) + { + let init_ha_node_containers_key = + YamlKey::try_from(".base.initHaNodeContainers.containers")?; + + yq.delete_object( + init_ha_node_containers_key.clone(), + upgrade_values_file.path(), + )?; + + for container in target_values.base_init_ha_node_containers() { + let container_val = serde_json::to_string(container).context( + SerializeBaseInitHaNodeContainersToJson { + object: container.clone(), + }, + )?; + yq.append_to_array( + init_ha_node_containers_key.clone(), + container_val, + upgrade_values_file.path(), + )?; + } + } + + // if base.initRestContainer.initContainer elements contain the image key + if source_values + .base_init_rest_container() + .iter() + .filter_map(|container| container.image.clone()) + .collect::>() + .contains(&image_tag_to_remove) + { + let init_rest_container_key = + YamlKey::try_from(".base.initRestContainer.initContainer")?; + + yq.delete_object(init_rest_container_key.clone(), upgrade_values_file.path())?; + + for container in target_values.base_init_rest_container() { + let container_val = serde_json::to_string(container).context( + SerializeBaseInitRestContainerToJson { + object: container.clone(), + }, + )?; + yq.append_to_array( + init_rest_container_key.clone(), + container_val, + upgrade_values_file.path(), + )?; + } + } + + // if the base.jaeger.agent.initContainer index contain the image key + if source_values + .base_jaeger_agent_init_container() + .iter() + .filter_map(|container| container.image.clone()) + .collect::>() + .contains(&image_tag_to_remove) + { + let jaeger_agent_init_container_key = + YamlKey::try_from(".base.jaeger.agent.initContainer")?; + + yq.delete_object( + jaeger_agent_init_container_key.clone(), + upgrade_values_file.path(), + )?; + + for container in target_values.base_jaeger_agent_init_container() { + let container_val = serde_json::to_string(container).context( + SerializeJaegerAgentInitContainerToJson { + object: container.clone(), + }, + )?; + yq.append_to_array( + jaeger_agent_init_container_key.clone(), + container_val, + upgrade_values_file.path(), + )?; + } + } + } + + // Special-case values for 2.7.3. + let two_dot_seven_dot_three = Version::parse(TWO_DOT_SEVEN_DOT_THREE).context(SemverParse { + version_string: TWO_DOT_SEVEN_DOT_THREE.to_string(), + })?; + if source_version.ge(&two_dot_o_rc_zero) && source_version.lt(&two_dot_seven_dot_three) { + yq.delete_object( + YamlKey::try_from(".etcd.initialClusterState")?, + upgrade_values_file.path(), + )?; } // Default options. @@ -423,6 +562,16 @@ where target_values.csi_resizer_image_tag(), upgrade_values_file.path(), )?; + yq.set_literal_value( + YamlKey::try_from(".localpv-provisioner.localpv.image.tag")?, + target_values.localpv_provisioner_image_tag(), + upgrade_values_file.path(), + )?; + yq.set_literal_value( + YamlKey::try_from(".localpv-provisioner.helperPod.image.tag")?, + target_values.localpv_helper_image_tag(), + upgrade_values_file.path(), + )?; // Disable CRD installation in case they already exist using helm values. safe_crd_install(upgrade_values_file.path(), &yq).await?;