From 6540685e7711413915f22115d24a344356e7e554 Mon Sep 17 00:00:00 2001 From: Niladri Halder Date: Mon, 16 Oct 2023 05:28:04 +0000 Subject: [PATCH 1/4] refactor(upgrade-job): remove use of semver::VersionReq Signed-off-by: Niladri Halder --- .../src/bin/upgrade-job/common/constants.rs | 15 +++++---- .../src/bin/upgrade-job/helm/values.rs | 31 ++++++++++++------- .../src/bin/upgrade-job/upgrade/utils.rs | 11 +++---- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/k8s/upgrade/src/bin/upgrade-job/common/constants.rs b/k8s/upgrade/src/bin/upgrade-job/common/constants.rs index 36fca302c..7ca2a1e6a 100644 --- a/k8s/upgrade/src/bin/upgrade-job/common/constants.rs +++ b/k8s/upgrade/src/bin/upgrade-job/common/constants.rs @@ -27,11 +27,14 @@ pub(crate) const TO_UMBRELLA_SEMVER: &str = "3.9.0"; pub(crate) const UMBRELLA_CHART_UPGRADE_DOCS_URL: &str = "https://openebs.io/docs/user-guides/upgrade#mayastor-upgrade"; -/// This defines the range of helm chart versions for the 2.0 release of the Core helm chart. -pub(crate) const TWO_DOT_O: &str = ">=2.0.0-rc.0, <2.1.0"; +/// Version value for the earliest possible 2.0 release. +pub(crate) const TWO_DOT_O_RC_ONE: &str = "2.0.0-rc.1"; -/// This defines the range of helm chart versions 2.1 and higher, of the Core helm chart. -pub(crate) const TWO_DOT_ONE_AND_UP: &str = ">=2.1.0"; +/// Version value for the earliest possible 2.1 release (there were no pre-releases). +pub(crate) const TWO_DOT_ONE: &str = "2.1.0"; -/// This defines the range of helm chart versions for the 2.3 release of the Core helm chart. -pub(crate) const TWO_DOT_THREE: &str = ">=2.3.0-rc.0, <2.4.0"; +/// Version value for the earliest possible 2.3 release (there were no pre-releases). +pub(crate) const TWO_DOT_THREE: &str = "2.3.0"; + +/// Version value for the earliest possible 2.4 release (there were no pre-releases). +pub(crate) const TWO_DOT_FOUR: &str = "2.4.0"; diff --git a/k8s/upgrade/src/bin/upgrade-job/helm/values.rs b/k8s/upgrade/src/bin/upgrade-job/helm/values.rs index f4da314c6..97586b7da 100644 --- a/k8s/upgrade/src/bin/upgrade-job/helm/values.rs +++ b/k8s/upgrade/src/bin/upgrade-job/helm/values.rs @@ -1,6 +1,6 @@ use crate::{ common::{ - constants::{TWO_DOT_O, TWO_DOT_ONE_AND_UP, TWO_DOT_THREE}, + constants::{TWO_DOT_FOUR, TWO_DOT_ONE, TWO_DOT_O_RC_ONE, TWO_DOT_THREE}, error::{ ReadingFile, Result, SemverParse, TempFileCreation, U8VectorToString, WriteToTempFile, YamlParseFromFile, YamlParseFromSlice, @@ -12,7 +12,7 @@ use crate::{ yaml::yq::{YamlKey, YqV4}, }, }; -use semver::{Version, VersionReq}; +use semver::Version; use snafu::ResultExt; use std::{fs, io::Write, path::Path, str}; use tempfile::NamedTempFile as TempFile; @@ -64,11 +64,18 @@ pub(crate) fn generate_values_yaml_file( filepath: upgrade_values_file.path().to_path_buf(), })?; + // Not using semver::VersionReq because expressions like '>=2.1.0' don't include + // 2.3.0-rc.0. 2.3.0, 2.4.0, etc. are supported. So, not using VersionReq in the + // below comparisons because of this. + // Specific special-case values for version 2.0.x. - let version_two_dot_o = VersionReq::parse(TWO_DOT_O).context(SemverParse { - version_string: TWO_DOT_O.to_string(), + let two_dot_o_rc_zero = Version::parse(TWO_DOT_O_RC_ONE).context(SemverParse { + version_string: TWO_DOT_O_RC_ONE.to_string(), + })?; + let two_dot_one = Version::parse(TWO_DOT_ONE).context(SemverParse { + version_string: TWO_DOT_ONE.to_string(), })?; - if version_two_dot_o.matches(from_version) { + if from_version.ge(&two_dot_o_rc_zero) && from_version.lt(&two_dot_one) { let log_level_to_replace = "info,io_engine=info"; if from_values.io_engine_log_level().eq(log_level_to_replace) @@ -83,11 +90,7 @@ pub(crate) fn generate_values_yaml_file( } // Specific special-case values for to-version >=2.1.x. - let version_two_dot_one_and_up = - VersionReq::parse(TWO_DOT_ONE_AND_UP).context(SemverParse { - version_string: TWO_DOT_ONE_AND_UP.to_string(), - })?; - if version_two_dot_one_and_up.matches(to_version) { + if to_version.ge(&two_dot_one) { // RepoTags fields will also be set to the values found in the target helm values file // (low_priority file). This is so integration tests which use specific repo commits can // upgrade to a custom helm chart. @@ -109,10 +112,14 @@ pub(crate) fn generate_values_yaml_file( } // Specific special-case values for version 2.3.x. - let version_two_dot_three = VersionReq::parse(TWO_DOT_THREE).context(SemverParse { + let two_dot_three = Version::parse(TWO_DOT_THREE).context(SemverParse { version_string: TWO_DOT_THREE.to_string(), })?; - if version_two_dot_three.matches(from_version) + let two_dot_four = Version::parse(TWO_DOT_FOUR).context(SemverParse { + version_string: TWO_DOT_FOUR.to_string(), + })?; + if from_version.ge(&two_dot_three) + && from_version.lt(&two_dot_four) && from_values .eventing_enabled() .ne(&to_values.eventing_enabled()) diff --git a/k8s/upgrade/src/bin/upgrade-job/upgrade/utils.rs b/k8s/upgrade/src/bin/upgrade-job/upgrade/utils.rs index efa666779..4457c6f65 100644 --- a/k8s/upgrade/src/bin/upgrade-job/upgrade/utils.rs +++ b/k8s/upgrade/src/bin/upgrade-job/upgrade/utils.rs @@ -8,7 +8,7 @@ use crate::common::{ use k8s_openapi::api::core::v1::Pod; use kube::{api::ObjectList, ResourceExt}; use openapi::models::{Volume, VolumeStatus}; -use semver::{Version, VersionReq}; +use semver::Version; use snafu::ResultExt; use std::{collections::HashSet, time::Duration}; use tracing::{info, warn}; @@ -179,10 +179,9 @@ pub(crate) async fn data_plane_is_upgraded( to_version: &str, io_engine_pod_list: &ObjectList, ) -> Result { - let to_version_requirement: VersionReq = - VersionReq::parse(to_version).context(SemverParse { - version_string: to_version.to_string(), - })?; + let to_version_requirement: Version = Version::parse(to_version).context(SemverParse { + version_string: to_version.to_string(), + })?; for pod in io_engine_pod_list { let version_str = pod.labels().get(CHART_VERSION_LABEL_KEY).ok_or( @@ -202,7 +201,7 @@ pub(crate) async fn data_plane_is_upgraded( let version = Version::parse(version_str).context(SemverParse { version_string: version_str.clone(), })?; - if !to_version_requirement.matches(&version) { + if !to_version_requirement.eq(&version) { return Ok(false); } } From aafda22424b178f9898e33e77e20c304e9e5d1d9 Mon Sep 17 00:00:00 2001 From: Niladri Halder Date: Mon, 16 Oct 2023 14:49:42 +0000 Subject: [PATCH 2/4] feat(upgrade): fail when upgrading from a stable version to an unstable one Signed-off-by: Niladri Halder --- .../src/plugin/preflight_validations.rs | 34 +++++++++++++++++-- k8s/upgrade/src/plugin/upgrade.rs | 6 ++++ k8s/upgrade/src/plugin/user_prompt.rs | 6 +++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/k8s/upgrade/src/plugin/preflight_validations.rs b/k8s/upgrade/src/plugin/preflight_validations.rs index ed49a3f37..80206fe39 100644 --- a/k8s/upgrade/src/plugin/preflight_validations.rs +++ b/k8s/upgrade/src/plugin/preflight_validations.rs @@ -16,6 +16,7 @@ use serde::Deserialize; use serde_yaml; use snafu::ResultExt; use std::{collections::HashSet, ops::Deref, path::PathBuf}; +use utils::version_info; /// Validation to be done before applying upgrade. pub async fn preflight_check( @@ -36,7 +37,7 @@ pub async fn preflight_check( let rest_client = RestClient::new_with_config(config); if !resources.skip_upgrade_path_validation_for_unsupported_version { - upgrade_path_validation(namespace).await?; + upgrade_path_validation(namespace, resources.allow_unstable).await?; } if !resources.skip_replica_rebuild { @@ -185,7 +186,10 @@ impl TryFrom<&[u8]> for UnsupportedVersions { } } -pub(crate) async fn upgrade_path_validation(namespace: &str) -> error::Result<()> { +pub(crate) async fn upgrade_path_validation( + namespace: &str, + allow_unstable: bool, +) -> error::Result<()> { let unsupported_version_buf = &std::include_bytes!("../../config/unsupported_versions.yaml")[..]; let unsupported_versions = UnsupportedVersions::try_from(unsupported_version_buf) @@ -214,6 +218,32 @@ pub(crate) async fn upgrade_path_validation(namespace: &str) -> error::Result<() console_logger::error("", user_prompt::UPGRADE_TO_UNSUPPORTED_VERSION); return error::InvalidUpgradePath.fail(); } + + // Self version + let self_version_info = version_info!(); + let mut self_version: Option = None; + if let Some(tag) = self_version_info.version_tag { + if !tag.is_empty() { + if let Ok(sv) = Version::parse(tag.as_str()) { + self_version = Some(sv); + } + } + } + + // Stable to unstable check. + if !allow_unstable { + let mut self_is_stable: bool = false; + if let Some(version) = self_version { + if !version.pre.is_empty() { + self_is_stable = true; + } + } + if source.pre.is_empty() && !self_is_stable { + console_logger::error("", user_prompt::STABLE_TO_UNSTABLE_UPGRADE); + return error::InvalidUpgradePath.fail(); + } + } + Ok(()) } diff --git a/k8s/upgrade/src/plugin/upgrade.rs b/k8s/upgrade/src/plugin/upgrade.rs index a949d9b31..330669608 100644 --- a/k8s/upgrade/src/plugin/upgrade.rs +++ b/k8s/upgrade/src/plugin/upgrade.rs @@ -86,6 +86,11 @@ pub enum Actions { /// Arguments to be passed for upgrade. #[derive(Debug, Clone, clap::Args)] pub struct UpgradeArgs { + /// Allow upgrade from stable versions to unstable versions. This is implied when the + /// '--skip-upgrade-path-validation-for-unsupported-version' option is used. + #[clap(global = true, long, hide = true)] + pub allow_unstable: bool, + /// Display all the validations output but will not execute upgrade. #[clap(global = true, long, short)] pub dry_run: bool, @@ -131,6 +136,7 @@ impl UpgradeArgs { /// Initialise with default values. pub fn new() -> Self { Self { + allow_unstable: false, dry_run: false, skip_data_plane_restart: false, skip_single_replica_volume_validation: false, diff --git a/k8s/upgrade/src/plugin/user_prompt.rs b/k8s/upgrade/src/plugin/user_prompt.rs index 77bd76e74..f3d7a2465 100644 --- a/k8s/upgrade/src/plugin/user_prompt.rs +++ b/k8s/upgrade/src/plugin/user_prompt.rs @@ -49,8 +49,12 @@ pub const UPGRADE_TO_UNSUPPORTED_VERSION: &str = /// Delete an incomplete job. pub const DELETE_INCOMPLETE_JOB: &str = - "\n Cant delete an incomplete upgrade job. Please try with `--force` flag to forcefully remove upgrade resources and bypass graceful deletion."; + "\nCan't delete an incomplete upgrade job. Please try with `--force` flag to forcefully remove upgrade resources and bypass graceful deletion."; /// Information about successful start of upgrade process. pub const HELM_UPGRADE_VALIDATION_ERROR: &str = "\nThe validation for upgrade Failed, hence deleting the upgrade resources. Please re-run upgrade with valid values."; + +/// Failure notice for when upgrading from a stable version to an unstable version. +pub const STABLE_TO_UNSTABLE_UPGRADE: &str = + "Cannot upgrade from a stable version to an unstable version"; From 5f130d7901ec184dd4598058c6d03aefb19efb93 Mon Sep 17 00:00:00 2001 From: Niladri Halder Date: Mon, 16 Oct 2023 14:53:06 +0000 Subject: [PATCH 3/4] feat(upgrade): fail when upgrading from a higher to a lower version Signed-off-by: Niladri Halder --- k8s/upgrade/src/plugin/preflight_validations.rs | 10 +++++++++- k8s/upgrade/src/plugin/user_prompt.rs | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/k8s/upgrade/src/plugin/preflight_validations.rs b/k8s/upgrade/src/plugin/preflight_validations.rs index 80206fe39..374063bce 100644 --- a/k8s/upgrade/src/plugin/preflight_validations.rs +++ b/k8s/upgrade/src/plugin/preflight_validations.rs @@ -233,7 +233,7 @@ pub(crate) async fn upgrade_path_validation( // Stable to unstable check. if !allow_unstable { let mut self_is_stable: bool = false; - if let Some(version) = self_version { + if let Some(ref version) = self_version { if !version.pre.is_empty() { self_is_stable = true; } @@ -244,6 +244,14 @@ pub(crate) async fn upgrade_path_validation( } } + // Upgrade not allowed to lower semver versions check. + if let Some(ref version) = self_version { + if version.lt(&source) { + console_logger::error("", user_prompt::HIGHER_TO_LOWER_SEMVER_UPGRADE); + return error::InvalidUpgradePath.fail(); + } + } + Ok(()) } diff --git a/k8s/upgrade/src/plugin/user_prompt.rs b/k8s/upgrade/src/plugin/user_prompt.rs index f3d7a2465..5a0cfd964 100644 --- a/k8s/upgrade/src/plugin/user_prompt.rs +++ b/k8s/upgrade/src/plugin/user_prompt.rs @@ -58,3 +58,8 @@ pub const HELM_UPGRADE_VALIDATION_ERROR: &str = /// Failure notice for when upgrading from a stable version to an unstable version. pub const STABLE_TO_UNSTABLE_UPGRADE: &str = "Cannot upgrade from a stable version to an unstable version"; + +/// Failure notice for when upgrading from a higher version to a lower one. +pub const HIGHER_TO_LOWER_SEMVER_UPGRADE: &str = + "Cannot upgrade from a higher version to a lower version. \ +If this is intentional, try again with '--skip-upgrade-path-validation-for-unsupported-version'"; From e954b4e8b4f875ed3fbf02a53e1f4b710e682032 Mon Sep 17 00:00:00 2001 From: Niladri Halder Date: Mon, 16 Oct 2023 14:55:29 +0000 Subject: [PATCH 4/4] build: allow a 'v' prefix when using the main-unstable tag Signed-off-by: Niladri Halder --- nix/pkgs/images/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/pkgs/images/default.nix b/nix/pkgs/images/default.nix index 570743fc6..b909096ab 100644 --- a/nix/pkgs/images/default.nix +++ b/nix/pkgs/images/default.nix @@ -46,7 +46,7 @@ let # Script doesn't need to be used with main branch `--alias-tag `. # The repo chart is already prepared. if [[ "$(semver validate ${tag})" == "valid" ]] && - [[ ! ${tag} =~ ^([0-9]+\.[0-9]+\.[0-9]+-0-main-unstable(-[0-9]+){6}-0)$ ]]; then + [[ ! ${tag} =~ ^(v?[0-9]+\.[0-9]+\.[0-9]+-0-main-unstable(-[0-9]+){6}-0)$ ]]; then CHART_FILE=build/chart/Chart.yaml build/scripts/helm/publish-chart-yaml.sh --app-tag ${tag} --override-index "" fi chmod -w build/chart