Merge "Introduce multi-version auto downgrade for apps"

This commit is contained in:
Zuul 2024-04-18 17:53:43 +00:00 committed by Gerrit Code Review
commit 37beadd020
3 changed files with 43 additions and 10 deletions

View File

@ -381,6 +381,13 @@ def validate_metadata_file(path, metadata_file, upgrade_from_release=None):
for version in from_versions: for version in from_versions:
validate_string(version) validate_string(version)
# Downgrades section validation
downgrades = validate_dict_field(doc, constants.APP_METADATA_DOWNGRADES)
if downgrades:
validate_boolstr_field(
downgrades,
constants.APP_METADATA_AUTO_DOWNGRADE)
# Kubernetes version section validation # Kubernetes version section validation
k8s_version = validate_k8s_version(doc) k8s_version = validate_k8s_version(doc)
if k8s_version: if k8s_version:

View File

@ -1988,6 +1988,9 @@ APP_METADATA_UPGRADES = 'upgrades'
APP_METADATA_UPDATE_FAILURE_SKIP_RECOVERY = 'update_failure_no_rollback' APP_METADATA_UPDATE_FAILURE_SKIP_RECOVERY = 'update_failure_no_rollback'
APP_METADATA_AUTO_UPDATE = 'auto_update' APP_METADATA_AUTO_UPDATE = 'auto_update'
APP_METADATA_AUTO_UPDATE_DEFAULT_VALUE = True APP_METADATA_AUTO_UPDATE_DEFAULT_VALUE = True
APP_METADATA_DOWNGRADES = 'downgrades'
APP_METADATA_AUTO_DOWNGRADE = 'auto_downgrade'
APP_METADATA_AUTO_DOWNGRADE_DEFAULT_VALUE = True
APP_METADATA_FAILED_VERSIONS = 'failed_versions' APP_METADATA_FAILED_VERSIONS = 'failed_versions'
APP_METADATA_FROM_VERSIONS = 'from_versions' APP_METADATA_FROM_VERSIONS = 'from_versions'
APP_METADATA_SUPPORTED_K8S_VERSION = 'supported_k8s_version' APP_METADATA_SUPPORTED_K8S_VERSION = 'supported_k8s_version'

View File

@ -53,6 +53,7 @@ import xml.etree.ElementTree as ElementTree
from contextlib import contextmanager from contextlib import contextmanager
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
from distutils.util import strtobool
from distutils.version import LooseVersion from distutils.version import LooseVersion
from copy import deepcopy from copy import deepcopy
from urllib3.exceptions import MaxRetryError from urllib3.exceptions import MaxRetryError
@ -7805,6 +7806,11 @@ class ConductorManager(service.PeriodicService):
True, True,
k8s_upgrade_timing) k8s_upgrade_timing)
auto_downgrade = strtobool(app.app_metadata.get(constants.APP_METADATA_DOWNGRADES, {})
.get(constants.APP_METADATA_AUTO_DOWNGRADE,
str(constants.APP_METADATA_AUTO_DOWNGRADE_DEFAULT_VALUE)))
latest_downgrade_bundle = None
available_versions = set()
latest_version_bundle = None latest_version_bundle = None
if k8s_version is None: if k8s_version is None:
@ -7813,15 +7819,8 @@ class ConductorManager(service.PeriodicService):
k8s_version = k8s_version.strip().lstrip('v') k8s_version = k8s_version.strip().lstrip('v')
for bundle_metadata in bundle_metadata_list: for bundle_metadata in bundle_metadata_list:
if LooseVersion(bundle_metadata.version) <= LooseVersion(app.app_version): available_versions.add(bundle_metadata.version)
LOG.debug("Bundle {} version {} lower than installed app version ({})" if LooseVersion(k8s_version) < LooseVersion(bundle_metadata.k8s_minimum_version):
.format(bundle_metadata.file_path,
bundle_metadata.version,
app.app_version))
elif not bundle_metadata.auto_update:
LOG.debug("Application auto update disabled for bundle {}"
.format(bundle_metadata.file_path))
elif LooseVersion(k8s_version) < LooseVersion(bundle_metadata.k8s_minimum_version):
LOG.debug("Kubernetes version {} is lower than {} which is " LOG.debug("Kubernetes version {} is lower than {} which is "
"the minimum required for bundle {}" "the minimum required for bundle {}"
.format(k8s_version, .format(k8s_version,
@ -7834,6 +7833,21 @@ class ConductorManager(service.PeriodicService):
.format(k8s_version, .format(k8s_version,
bundle_metadata.k8s_maximum_version, bundle_metadata.k8s_maximum_version,
bundle_metadata.file_path)) bundle_metadata.file_path))
elif LooseVersion(bundle_metadata.version) == LooseVersion(app.app_version):
LOG.debug("Bundle {} version and installed app version are the same ({})"
.format(bundle_metadata.file_path,
app.app_version))
elif LooseVersion(bundle_metadata.version) < LooseVersion(app.app_version):
LOG.debug("Bundle {} version {} is lower than installed app version ({})"
.format(bundle_metadata.file_path,
bundle_metadata.version,
app.app_version))
if (latest_downgrade_bundle is None or LooseVersion(bundle_metadata.version) >
LooseVersion(latest_downgrade_bundle.version)):
latest_downgrade_bundle = bundle_metadata
elif not bundle_metadata.auto_update:
LOG.debug("Application auto update disabled for bundle {}"
.format(bundle_metadata.file_path))
elif ((latest_version_bundle is None) or elif ((latest_version_bundle is None) or
(LooseVersion(bundle_metadata.version) > (LooseVersion(bundle_metadata.version) >
LooseVersion(latest_version_bundle.version))): LooseVersion(latest_version_bundle.version))):
@ -7841,6 +7855,15 @@ class ConductorManager(service.PeriodicService):
# of the current one is higher than the one previously set. # of the current one is higher than the one previously set.
latest_version_bundle = bundle_metadata latest_version_bundle = bundle_metadata
# Downgrade if the installed app version is not available anymore and an older compatible
# bundle is available instead.
if (auto_downgrade and
app.app_version not in available_versions and
latest_downgrade_bundle is not None):
LOG.info("Application {} will be downgraded from version {} to {}"
.format(app.name, app.app_version, latest_downgrade_bundle.version))
return latest_downgrade_bundle
return latest_version_bundle return latest_version_bundle
def _auto_update_app(self, def _auto_update_app(self,