core: Move package version helpers to BaseOpenStackCharmActions

To resolve a inter-dependency issue between the various package
version helpers and the UCA ``configure_source`` method, co-locate
all of them in ``BaseOpenStackCharmActions``.

Partial-Bug: #1951462
Change-Id: If42ad980ff2b0430eba24531eae9a80204768388
This commit is contained in:
Frode Nordahl 2022-02-25 11:22:53 +01:00
parent fd6581ecab
commit dda431eaf9
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
2 changed files with 185 additions and 186 deletions

View File

@ -533,186 +533,6 @@ class BaseOpenStackCharm(object, metaclass=BaseOpenStackCharmMeta):
"""proxy for charms.reactive.bus.get_state()"""
return reactive.bus.get_state(state)
@staticmethod
def get_os_codename_snap(snap, codenames, fatal=True):
"""Derive OpenStack release codename from an installed snap.
:param package: str Snap name to lookup (ie. in snap list)
:param codenames: dict of OrderedDict
{
'snap1': collections.OrderedDict([
('2', 'mitaka'),
('3', 'newton'),
('4', 'ocata'), ]),
'snap2': collections.OrderedDict([
('12', 'mitaka'),
('13', 'newton'),
('14', 'ocata'), ]),
}
:param fatal: bool Raise exception if snap not installed
:returns: str OpenStack version name corresponding to package
"""
version_or_codename = get_snap_version(snap, fatal)
match = re.match(r'^(\d+)\.(\d+)', version_or_codename)
if match:
version = match.group(0)
# Generate a major version number for newer semantic
# versions of openstack projects
major_vers = version.split('.')[0]
try:
return codenames[snap][major_vers]
except KeyError:
# NOTE(jamespage): fallthrough to codename assumption
pass
# NOTE(jamespage): fallback to codename assumption
return version_or_codename
@staticmethod
def get_package_version(package, apt_cache_sufficient=False):
"""Derive OpenStack release codename from a package.
:param package: Package name to lookup (ie. in apt cache)
:type package: str
:param apt_cache_sufficient: When False (the default) version from an
installed package will be used, when True version from the systems
APT cache will be used. This is useful for subordinate charms who
need working release selection prior to package installation and
has no way of using fall back to version of a package the principle
charm has installed nor package source configuration option.
:type apt_cache_sufficient: bool
:returns: OpenStack version name corresponding to package
:rtype: Optional[str]
:raises: AttributeError, ValueError
"""
cache = fetch.apt_cache()
try:
pkg = cache[package]
except KeyError:
# the package is unknown to the current apt cache.
e = ValueError(
'Could not determine version of package with no installation '
'candidate: {}'.format(package))
raise e
if apt_cache_sufficient:
vers = fetch.apt_pkg.upstream_version(pkg.version)
else:
vers = fetch.apt_pkg.upstream_version(pkg.current_ver.ver_str)
# x.y match only for 20XX.X
# and ignore patch level for other packages
match = re.match(r'^(\d+)\.(\d+)', vers)
if match:
vers = match.group(0)
return vers
@staticmethod
def get_os_codename_package(package, codenames, fatal=True,
apt_cache_sufficient=False):
"""Derive OpenStack release codename from a package.
Initially, see if the openstack-release pkg is available (by trying
to install it) and use it instead.
If it isn't then it falls back to the existing method of checking the
version of the package passed and then resolving the version from that
using lookup tables.
:param package: Package name to lookup (ie. in apt cache)
:type package: str
:param codenames: Map of package to (version, os_release) tuples.
Example:
{
'pkg1': collections.OrderedDict([
('2', 'mitaka'),
('3', 'newton'),
('4', 'ocata'), ]),
'pkg2': collections.OrderedDict([
('12.6', 'mitaka'),
('13.2', 'newton'),
('14.7', 'ocata'), ]),
}
:type codenames: Dict[str,collections.OrderedDict[Tuple(str,str)]]
:param fatal: Raise exception if pkg not installed
:type fatal: bool
:param apt_cache_sufficient: When False (the default) version from an
installed package will be used, when True version from the systems
APT cache will be used. This is useful for subordinate charms who
need working release selection prior to package installation and
has no way of using fall back to version of a package the principle
charm has installed nor package source configuration option.
:type apt_cache_sufficient: bool
:returns: OpenStack version name corresponding to package
:rtype: Optional[str]
:raises: AttributeError, ValueError
"""
codename = os_utils.get_installed_os_version()
if codename:
return codename
try:
vers = BaseOpenStackCharm.get_package_version(
package,
apt_cache_sufficient=apt_cache_sufficient)
# Generate a major version number for newer semantic
# versions of openstack projects
major_vers = vers.split('.')[0]
except Exception:
if fatal:
raise
else:
return None
if (package in codenames and
major_vers in codenames[package]):
return codenames[package][major_vers]
def get_os_version_snap(self, snap, fatal=True):
"""Derive OpenStack version number from an installed snap.
:param package: str Snap name to lookup in snap list
:param fatal: bool Raise exception if snap not installed
:returns: str OpenStack version number corresponding to snap
"""
if os_utils.snap_install_requested():
codename = self.get_os_codename_snap(snap,
self.snap_codenames,
fatal=fatal)
if not codename:
return None
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
if cname == codename:
return version
return None
def get_os_version_package(self, package, fatal=True):
"""Derive OpenStack version number from an installed package.
:param package: str Package name to lookup in apt cache
:param fatal: bool Raise exception if pkg not installed
:returns: str OpenStack version number corresponding to package
"""
if not os_utils.snap_install_requested():
codename = self.get_os_codename_package(
package, self.package_codenames or os_utils.PACKAGE_CODENAMES,
fatal=fatal)
if not codename:
return None
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
if cname == codename:
return version
return None
class BaseOpenStackCharmActions(object):
"""Default actions that an OpenStack charm can expect to have to do.
@ -1265,6 +1085,185 @@ class BaseOpenStackCharmActions(object):
"""
return self.config[self.source_config_key].startswith('snap:')
@staticmethod
def get_os_codename_snap(snap, codenames, fatal=True):
"""Derive OpenStack release codename from an installed snap.
:param package: str Snap name to lookup (ie. in snap list)
:param codenames: dict of OrderedDict
{
'snap1': collections.OrderedDict([
('2', 'mitaka'),
('3', 'newton'),
('4', 'ocata'), ]),
'snap2': collections.OrderedDict([
('12', 'mitaka'),
('13', 'newton'),
('14', 'ocata'), ]),
}
:param fatal: bool Raise exception if snap not installed
:returns: str OpenStack version name corresponding to package
"""
version_or_codename = get_snap_version(snap, fatal)
match = re.match(r'^(\d+)\.(\d+)', version_or_codename)
if match:
version = match.group(0)
# Generate a major version number for newer semantic
# versions of openstack projects
major_vers = version.split('.')[0]
try:
return codenames[snap][major_vers]
except KeyError:
# NOTE(jamespage): fallthrough to codename assumption
pass
# NOTE(jamespage): fallback to codename assumption
return version_or_codename
@staticmethod
def get_package_version(package, apt_cache_sufficient=False):
"""Derive OpenStack release codename from a package.
:param package: Package name to lookup (ie. in apt cache)
:type package: str
:param apt_cache_sufficient: When False (the default) version from an
installed package will be used, when True version from the systems
APT cache will be used. This is useful for subordinate charms who
need working release selection prior to package installation and
has no way of using fall back to version of a package the principle
charm has installed nor package source configuration option.
:type apt_cache_sufficient: bool
:returns: OpenStack version name corresponding to package
:rtype: Optional[str]
:raises: AttributeError, ValueError
"""
cache = fetch.apt_cache()
try:
pkg = cache[package]
except KeyError:
# the package is unknown to the current apt cache.
e = ValueError(
'Could not determine version of package with no installation '
'candidate: {}'.format(package))
raise e
if apt_cache_sufficient:
vers = fetch.apt_pkg.upstream_version(pkg.version)
else:
vers = fetch.apt_pkg.upstream_version(pkg.current_ver.ver_str)
# x.y match only for 20XX.X
# and ignore patch level for other packages
match = re.match(r'^(\d+)\.(\d+)', vers)
if match:
vers = match.group(0)
return vers
def get_os_codename_package(self, package, codenames, fatal=True,
apt_cache_sufficient=False):
"""Derive OpenStack release codename from a package.
Initially, see if the openstack-release pkg is available (by trying
to install it) and use it instead.
If it isn't then it falls back to the existing method of checking the
version of the package passed and then resolving the version from that
using lookup tables.
:param package: Package name to lookup (ie. in apt cache)
:type package: str
:param codenames: Map of package to (version, os_release) tuples.
Example:
{
'pkg1': collections.OrderedDict([
('2', 'mitaka'),
('3', 'newton'),
('4', 'ocata'), ]),
'pkg2': collections.OrderedDict([
('12.6', 'mitaka'),
('13.2', 'newton'),
('14.7', 'ocata'), ]),
}
:type codenames: Dict[str,collections.OrderedDict[Tuple(str,str)]]
:param fatal: Raise exception if pkg not installed
:type fatal: bool
:param apt_cache_sufficient: When False (the default) version from an
installed package will be used, when True version from the systems
APT cache will be used. This is useful for subordinate charms who
need working release selection prior to package installation and
has no way of using fall back to version of a package the principle
charm has installed nor package source configuration option.
:type apt_cache_sufficient: bool
:returns: OpenStack version name corresponding to package
:rtype: Optional[str]
:raises: AttributeError, ValueError
"""
codename = os_utils.get_installed_os_version()
if codename:
return codename
try:
vers = self.get_package_version(
package,
apt_cache_sufficient=apt_cache_sufficient)
# Generate a major version number for newer semantic
# versions of openstack projects
major_vers = vers.split('.')[0]
except Exception:
if fatal:
raise
else:
return None
if (package in codenames and
major_vers in codenames[package]):
return codenames[package][major_vers]
def get_os_version_snap(self, snap, fatal=True):
"""Derive OpenStack version number from an installed snap.
:param package: str Snap name to lookup in snap list
:param fatal: bool Raise exception if snap not installed
:returns: str OpenStack version number corresponding to snap
"""
if os_utils.snap_install_requested():
codename = self.get_os_codename_snap(snap,
self.snap_codenames,
fatal=fatal)
if not codename:
return None
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
if cname == codename:
return version
return None
def get_os_version_package(self, package, fatal=True):
"""Derive OpenStack version number from an installed package.
:param package: str Package name to lookup in apt cache
:param fatal: bool Raise exception if pkg not installed
:returns: str OpenStack version number corresponding to package
"""
if not os_utils.snap_install_requested():
codename = self.get_os_codename_package(
package, self.package_codenames or os_utils.PACKAGE_CODENAMES,
fatal=fatal)
if not codename:
return None
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
if cname == codename:
return version
return None
class BaseOpenStackCharmAssessStatus(object):
"""Provides the 'Assess Status' functionality to the OpenStack charm class.

View File

@ -903,14 +903,14 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
self.get_installed_os_version.return_value = None
self.upstream_version.return_value = '3.0.0~b1'
self.assertEqual(
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'testpkg', codenames),
'newton')
self.upstream_version.assert_called_once_with(
pkg_mock.current_ver.ver_str)
self.upstream_version.reset_mock()
self.assertEqual(
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'testpkg', codenames, apt_cache_sufficient=True),
'newton')
self.upstream_version.assert_called_once_with(
@ -918,21 +918,21 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
# Test Wallaby
self.get_installed_os_version.return_value = 'wallaby'
self.assertEqual(
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'testpkg', codenames),
'wallaby')
# Test non-fatal fail
self.get_installed_os_version.return_value = None
self.assertEqual(
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'unknownpkg', codenames, fatal=False),
None)
# Test fatal fail
with self.assertRaises(Exception):
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'unknownpkg', codenames, fatal=True)
with self.assertRaises(ValueError):
chm_core.BaseOpenStackCharm.get_os_codename_package(
self.target.get_os_codename_package(
'unknownpkg', codenames, fatal=True)
def test_get_os_version_package(self):