Ensure that series upgrades ignore percona at focal

When doing a series upgrade from bionic to focal, the percona-cluster
charm needs to be avoided.  This filters the applications for percona if
the target is focal.  Note if percona is placed on the same unit as
something else that needs to be upgraded (bad idea) then it may still
get 'upgraded' and the operation will fail.
This commit is contained in:
Alex Kavanagh
2021-11-30 18:50:14 +00:00
parent a0b4d15dc6
commit d4d415c859
6 changed files with 152 additions and 5 deletions

View File

@@ -116,6 +116,21 @@ class TestUpgradeUtils(ut_utils.BaseTestCase):
self.assertEqual(
actual,
expected)
# test that, at focal, there are no database services.
expected = [
('Database Services', []),
('Stateful Services', []),
('Core Identity', []),
('Control Plane', ['cinder']),
('Data Plane', ['nova-compute']),
('sweep_up', ['ntp'])]
actual = openstack_upgrade.get_series_upgrade_groups(
target_series='focal')
pprint.pprint(expected)
pprint.pprint(actual)
self.assertEqual(
actual,
expected)
def test_extract_charm_name_from_url(self):
self.assertEqual(

View File

@@ -26,8 +26,8 @@ import zaza.model
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.generic as generic_utils
from charmhelpers.core.host import CompareHostReleases
from zaza.openstack.utilities.generic import get_series
from zaza.openstack.utilities.os_versions import CompareHostReleases
from . import utils as rmq_utils
from .utils import RmqNoMessageException

View File

@@ -73,7 +73,8 @@ class ParallelSeriesUpgradeTest(unittest.TestCase):
# Set Feature Flag
os.environ["JUJU_DEV_FEATURE_FLAGS"] = "upgrade-series"
upgrade_groups = upgrade_utils.get_series_upgrade_groups(
extra_filters=[_filter_etcd, _filter_easyrsa])
extra_filters=[_filter_etcd, _filter_easyrsa],
target_series=self.to_series)
from_series = self.from_series
to_series = self.to_series
completed_machines = []

View File

@@ -193,7 +193,8 @@ class ParallelSeriesUpgradeTest(unittest.TestCase):
os.environ["JUJU_DEV_FEATURE_FLAGS"] = "upgrade-series"
upgrade_groups = upgrade_utils.get_series_upgrade_groups(
extra_filters=[upgrade_utils._filter_etcd,
upgrade_utils._filter_easyrsa])
upgrade_utils._filter_easyrsa],
target_series=self.to_series)
applications = model.get_status().applications
completed_machines = []
for group_name, group in upgrade_groups:

View File

@@ -278,3 +278,105 @@ PACKAGE_CODENAMES = {
('4', 'victoria'),
]),
}
UBUNTU_RELEASES = (
'lucid',
'maverick',
'natty',
'oneiric',
'precise',
'quantal',
'raring',
'saucy',
'trusty',
'utopic',
'vivid',
'wily',
'xenial',
'yakkety',
'zesty',
'artful',
'bionic',
'cosmic',
'disco',
'eoan',
'focal',
'groovy',
'hirsute',
'impish',
)
class BasicStringComparator(object):
"""Provides a class that will compare strings from an iterator type object.
Used to provide > and < comparisons on strings that may not necessarily be
alphanumerically ordered. e.g. OpenStack or Ubuntu releases AFTER the
z-wrap.
"""
_list = None
def __init__(self, item):
"""Do init."""
if self._list is None:
raise Exception("Must define the _list in the class definition!")
try:
self.index = self._list.index(item)
except Exception:
raise KeyError("Item '{}' is not in list '{}'"
.format(item, self._list))
def __eq__(self, other):
"""Do equals."""
assert isinstance(other, str) or isinstance(other, self.__class__)
return self.index == self._list.index(other)
def __ne__(self, other):
"""Do not equals."""
return not self.__eq__(other)
def __lt__(self, other):
"""Do less than."""
assert isinstance(other, str) or isinstance(other, self.__class__)
return self.index < self._list.index(other)
def __ge__(self, other):
"""Do greater than or equal."""
return not self.__lt__(other)
def __gt__(self, other):
"""Do greater than."""
assert isinstance(other, str) or isinstance(other, self.__class__)
return self.index > self._list.index(other)
def __le__(self, other):
"""Do less than or equals."""
return not self.__gt__(other)
def __str__(self):
"""Give back the item at the index.
This is so it can be used in comparisons like:
s_mitaka = CompareOpenStack('mitaka')
s_newton = CompareOpenstack('newton')
assert s_newton > s_mitaka
:returns: <string>
"""
return self._list[self.index]
class CompareHostReleases(BasicStringComparator):
"""Provide comparisons of Ubuntu releases.
Use in the form of
if CompareHostReleases(release) > 'trusty':
# do something with mitaka
"""
_list = UBUNTU_RELEASES

View File

@@ -24,6 +24,7 @@ from zaza.openstack.utilities.os_versions import (
OPENSTACK_CODENAMES,
UBUNTU_OPENSTACK_RELEASE,
OPENSTACK_RELEASES_PAIRS,
CompareHostReleases,
)
"""
@@ -96,6 +97,25 @@ def _filter_openstack_upgrade_list(app, app_config, model_name=None):
return False
def _make_filter_percona_cluster_at(target_series):
def _filter_percona_cluster(app, app_config, model_name=None):
charm_name = extract_charm_name_from_url(app_config['charm'])
if charm_name == "percona-cluster":
logging.warning(
"Excluding percona-cluster from upgrade, "
"as no candidate in %s", target_series)
return True
return False
def _noop_filter(*args, **kwargs):
return False
if target_series and CompareHostReleases(target_series) >= "focal":
return _filter_percona_cluster
return _noop_filter
def _filter_non_openstack_services(app, app_config, model_name=None):
charm_options = zaza.model.get_application_config(
app, model_name=model_name).keys()
@@ -168,7 +188,8 @@ def get_upgrade_groups(model_name=None, extra_filters=None):
return _build_service_groups(apps_in_model)
def get_series_upgrade_groups(model_name=None, extra_filters=None):
def get_series_upgrade_groups(model_name=None, extra_filters=None,
target_series=None):
"""Place apps in the model into their upgrade groups.
Place apps in the model into their upgrade groups. If an app is deployed
@@ -176,10 +197,17 @@ def get_series_upgrade_groups(model_name=None, extra_filters=None):
:param model_name: Name of model to query.
:type model_name: str
:param extra_filters: filters to apply to the upgrade groups
:type extra_filters: Callable
:param target_series: The series that will be series upgraded to.
:type target_series: Optional[str]
:returns: List of tuples(group name, applications)
:rtype: List[Tuple[str, Dict[str, ANY]]]
"""
filters = [_filter_subordinates]
filters = [
_filter_subordinates,
_make_filter_percona_cluster_at(target_series),
]
filters = _apply_extra_filters(filters, extra_filters)
apps_in_model = get_upgrade_candidates(
model_name=model_name,