From ccb778f11148717f99ce788098dabd76f0cdedae Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Thu, 18 Mar 2021 15:05:25 +0100 Subject: [PATCH] core: Add all supported releases - packages map For principal - subordinate plugin type relations where the principal Python payload imports code from packages managed by a subordinate, upgrades can be problematic. This helper will allow a subordinate charm to inform its principal about all implemented release - packages combinations ahead of time. With this information in place the principal can do the upgrade in one operation without risk of charm relation RPC type processing at a critical moment. Related-Bug: #1806111 Change-Id: I455501c1c2cdb53e62b533be95d2493bf1a5027a --- charms_openstack/charm/core.py | 34 ++++++++++++++ .../charms_openstack/charm/test_core.py | 47 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/charms_openstack/charm/core.py b/charms_openstack/charm/core.py index 39852df..1115c6e 100644 --- a/charms_openstack/charm/core.py +++ b/charms_openstack/charm/core.py @@ -391,6 +391,40 @@ class BaseOpenStackCharm(object, metaclass=BaseOpenStackCharmMeta): # Note refers back to the Metaclass property for this charm. return self.__class__.singleton + @property + def releases_packages_map(self): + """Provide a map of all supported releases and their packages. + + :returns: Map of release, package type and install / purge packages. + Example: + { + 'mitaka': { + 'deb': { + 'install': ['python-ldappool'], + 'purge': [] + } + }, + 'rocky': { + 'deb': { + 'install': ['python3-ldap', 'python3-ldappool'], + 'purge': ['python-ldap', 'python-ldappool']} + } + } + :rtype: Dict[str,Dict[str,List[str]]] + """ + return { + release: { + package_type: { + 'install': (instance.packages if package_type == 'deb' + else instance.snaps), + 'purge': (instance.purge_packages if package_type == 'deb' + else []), + }, + } + for release, pkg_instance in _releases.items() + for package_type, instance in pkg_instance.items() + } + def __init__(self, interfaces=None, config=None, release=None): """Instantiate an instance of the class. diff --git a/unit_tests/charms_openstack/charm/test_core.py b/unit_tests/charms_openstack/charm/test_core.py index 46b33ef..2b7d18f 100644 --- a/unit_tests/charms_openstack/charm/test_core.py +++ b/unit_tests/charms_openstack/charm/test_core.py @@ -127,6 +127,53 @@ class TestBaseOpenStackCharmMeta(BaseOpenStackCharmTest): class TestC2(chm_core.BaseOpenStackCharm): release = 'liberty' + def test_releases_packages_map(self): + self.maxDiff = None + self.patch_object(chm_core, '_releases', new={}) + + class TestC1(chm_core.BaseOpenStackCharm): + release = 'liberty' + packages = ['l_inst_one', 'l_inst_two'] + purge_packages = ['l_purge'] + + class TestC2(chm_core.BaseOpenStackCharm): + release = 'mitaka' + packages = ['m_inst_one', 'm_inst_two'] + purge_packages = ['m_purge'] + + class TestC3(chm_core.BaseOpenStackCharm): + release = 'ocata' + package_type = 'snap' + snaps = ['o_snap_one', 'o_snap_two'] + + # from any charm release instance we see package_type / install_purge + # lists registered by all other charm release instances + for cls in (TestC1, TestC2, TestC3): + instance = cls() + self.assertDictEqual( + instance.releases_packages_map, + { + 'liberty': { + 'deb': { + 'install': ['l_inst_one', 'l_inst_two'], + 'purge': ['l_purge'] + } + }, + 'mitaka': { + 'deb': { + 'install': ['m_inst_one', 'm_inst_two'], + 'purge': ['m_purge'] + } + }, + 'ocata': { + 'snap': { + 'install': ['o_snap_one', 'o_snap_two'], + 'purge': [] + } + } + } + ) + class TestFunctions(BaseOpenStackCharmTest):