Introduce multi-version auto downgrade for apps
Introduce automatic downgrade of StarlingX applications to the multiple application version feature. Auto downgrades are triggered by default in scenarios which the applied application bundle is not available anymore under the applications folder but an older version of the same app is. For instance, when platform patches are removed and a previously available ostree is deployed, thus restoring the old set of available apps under the /usr/local/share/applications/helm/ directory. A new section called 'downgrades' can be added to the metadata.yaml file to disable the default behavior. For example: downgrades: auto_downgrade: false When auto downgrades are disabled the current applied version remains unchanged. Test plan: PASS: build-pkgs -a && build-image PASS: AIO-SX fresh install. PASS: Apply platform-integ-apps. Update platform-integ-apps using a tarball that is not available under /usr/local/share/applications/helm/ and that does not contain the downgrade section. Confirm that platform-integ-apps is downgraded. PASS: Apply platform-integ-apps. Update platform-integ-apps using a tarball that is not available under /usr/local/share/applications/helm/ and that has the auto_downgrade metadata option set to 'true'. Confirm that platform-integ-apps is downgraded. PASS: Apply platform-integ-apps. Update platform-integ-apps using a tarball that is not available under /usr/local/share/applications/helm/ and that has the auto_downgrade metadata option set to 'false'. Confirm that the originally applied platform-integ-apps version remains unchanged. PASS: Run a kubernetes upgrade with apps to be pre and post updated. Confirm that apps are successfully updated and not downgraded after the Kubernetes upgrade has finished. Story: 2010929 Task: 49847 Change-Id: I33f0e0a5b8db128aef76fb93ba322364881097cf Signed-off-by: Igor Soares <Igor.PiresSoares@windriver.com>
This commit is contained in:
parent
82c95f934e
commit
1d228bab28
|
@ -125,7 +125,7 @@ def validate_metadata_file(path, metadata_file, upgrade_from_release=None):
|
|||
if not error_message:
|
||||
error_message = _("Invalid boolean value: {}"
|
||||
.format(value))
|
||||
raise exception.SysinvException(error_message)
|
||||
raise exception.SysinvException(error_message)
|
||||
|
||||
def validate_dict(value, error_message=None):
|
||||
"""Validate dictionary types"""
|
||||
|
@ -381,6 +381,13 @@ def validate_metadata_file(path, metadata_file, upgrade_from_release=None):
|
|||
for version in from_versions:
|
||||
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
|
||||
k8s_version = validate_k8s_version(doc)
|
||||
if k8s_version:
|
||||
|
|
|
@ -1982,6 +1982,9 @@ APP_METADATA_UPGRADES = 'upgrades'
|
|||
APP_METADATA_UPDATE_FAILURE_SKIP_RECOVERY = 'update_failure_no_rollback'
|
||||
APP_METADATA_AUTO_UPDATE = 'auto_update'
|
||||
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_FROM_VERSIONS = 'from_versions'
|
||||
APP_METADATA_SUPPORTED_K8S_VERSION = 'supported_k8s_version'
|
||||
|
|
|
@ -53,6 +53,7 @@ import xml.etree.ElementTree as ElementTree
|
|||
from contextlib import contextmanager
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from distutils.util import strtobool
|
||||
from distutils.version import LooseVersion
|
||||
from copy import deepcopy
|
||||
from urllib3.exceptions import MaxRetryError
|
||||
|
@ -7782,6 +7783,11 @@ class ConductorManager(service.PeriodicService):
|
|||
True,
|
||||
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
|
||||
|
||||
if k8s_version is None:
|
||||
|
@ -7790,15 +7796,8 @@ class ConductorManager(service.PeriodicService):
|
|||
k8s_version = k8s_version.strip().lstrip('v')
|
||||
|
||||
for bundle_metadata in bundle_metadata_list:
|
||||
if LooseVersion(bundle_metadata.version) <= LooseVersion(app.app_version):
|
||||
LOG.debug("Bundle {} version {} lower than installed app 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):
|
||||
available_versions.add(bundle_metadata.version)
|
||||
if LooseVersion(k8s_version) < LooseVersion(bundle_metadata.k8s_minimum_version):
|
||||
LOG.debug("Kubernetes version {} is lower than {} which is "
|
||||
"the minimum required for bundle {}"
|
||||
.format(k8s_version,
|
||||
|
@ -7811,6 +7810,21 @@ class ConductorManager(service.PeriodicService):
|
|||
.format(k8s_version,
|
||||
bundle_metadata.k8s_maximum_version,
|
||||
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
|
||||
(LooseVersion(bundle_metadata.version) >
|
||||
LooseVersion(latest_version_bundle.version))):
|
||||
|
@ -7818,6 +7832,15 @@ class ConductorManager(service.PeriodicService):
|
|||
# of the current one is higher than the one previously set.
|
||||
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
|
||||
|
||||
def _auto_update_app(self,
|
||||
|
|
Loading…
Reference in New Issue