From bae4fdbd45ba36d25c428da6a93213fab1b12a69 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Thu, 21 May 2020 17:24:55 +0100 Subject: [PATCH] LinuxPolicy: Make linux* wait on corresponding -meta package We want to treat linux-$flavor and linux-meta-$flavor as one set in britney which goes in together or not at all. We never want to promote linux-$flavor without the accompanying linux-meta-$flavor. Add a new LinuxPolicy which runs after most of the other policies, which invalidates linux-foo if linux-meta-foo is invalid. --- britney.py | 2 + britney2/policies/policy.py | 94 +++++++++++++++++++++++++++++++++++++ tests/test_autopkgtest.py | 53 +++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/britney.py b/britney.py index 2040596..9b5ce6c 100755 --- a/britney.py +++ b/britney.py @@ -213,6 +213,7 @@ from britney2.policies.policy import (AgePolicy, BuiltUsingPolicy, BuiltOnBuilddPolicy, ImplicitDependencyPolicy, + LinuxPolicy, LPBlockBugPolicy, ) from britney2.policies.autopkgtest import AutopkgtestPolicy @@ -526,6 +527,7 @@ class Britney(object): self._policy_engine.add_policy(BuiltOnBuilddPolicy(self.options, self.suite_info)) self._policy_engine.add_policy(LPBlockBugPolicy(self.options, self.suite_info)) self._policy_engine.add_policy(SourcePPAPolicy(self.options, self.suite_info)) + self._policy_engine.add_policy(LinuxPolicy(self.options, self.suite_info)) add_email_policy = getattr(self.options, 'email_enable', 'no') if add_email_policy in ('yes', 'dry-run'): self._policy_engine.add_policy(EmailPolicy(self.options, diff --git a/britney2/policies/policy.py b/britney2/policies/policy.py index 05b6335..b5a5dac 100644 --- a/britney2/policies/policy.py +++ b/britney2/policies/policy.py @@ -1810,3 +1810,97 @@ class LPBlockBugPolicy(BasePolicy): excuse.addreason('block') return PolicyVerdict.REJECTED_PERMANENTLY + + +class LinuxPolicy(BasePolicy): + """Make linux-* wait on linux-meta-*""" + + def __init__(self, options, suite_info): + super().__init__('linux', options, suite_info, {SuiteClass.PRIMARY_SOURCE_SUITE}) + self.metas = {} + self.invalidate = defaultdict(list) + + def initialise(self, britney): + super().initialise(britney) + self.britney = britney + + def meta_name(self, linux_source): + if linux_source.startswith('linux-signed'): + meta = linux_source.replace('linux-signed', 'linux-meta') + else: + meta = linux_source.replace('linux', 'linux-meta') + + return meta + + def find_meta_excuse(self, linux_source): + assert linux_source.startswith('linux') + + meta = self.meta_name(linux_source) + + try: + return self.metas[meta] + except KeyError: + return None + + def apply_src_policy_impl(self, linux_info, item, source_data_tdist, source_data_srcdist, excuse): + source_name = item.package + + if not source_name.startswith('linux'): + return PolicyVerdict.NOT_APPLICABLE + + self.logger.info("linux policy: considering %s", source_name) + + # If we're currently migrating a linux-meta package, look to see if we + # need to reject any of its corresponding linux packages. + if source_name.startswith('linux-meta'): + self.metas[source_name] = excuse + + # We're currently in the middle of running the policies for + # linux-meta, so we need to look at the *tentative* verdict. If + # it's rejected, then we will find any linux-* that we marked to + # come back to (see below), and handle them now. + if excuse.tentative_policy_verdict.is_rejected: + self.logger.info("%s is rejected, checking if we now need to reject anything else", source_name) + linux_excuses = self.invalidate[source_name] + if linux_excuses: + for linux_excuse in linux_excuses: + self.logger.info("%s is invalid, so invalidating %s too", + excuse.name, + linux_excuse.name) + linux_excuse.invalidate_externally(PolicyVerdict.REJECTED_WAITING_FOR_ANOTHER_ITEM) + linux_excuse.addreason("linux-meta-not-ready") + uvname = excuse.uvname + linux_excuse.add_verdict_info(linux_excuse.policy_verdict, + "%s is not a candidate" % (uvname, uvname)) + else: + self.logger.info("Nothing recorded to reject yet") + else: + self.logger.info("%s is a candidate, so we will not invalidate anything else", source_name) + return PolicyVerdict.PASS + + # Or we're migrating linux-*, so look to see if we already know about + # linux-meta-*, which will happen if we processed that excuse first. + linux_meta_excuse = self.find_meta_excuse(source_name) + + if not linux_meta_excuse: + # We don't know about linux-meta, but if it's in the source suite + # we will later, so remember to come back to this item then. + meta_name = self.meta_name(source_name) + self.logger.info("No excuse for %s yet, will come back to %s when visiting it later.", + meta_name, + excuse.name) + self.invalidate[meta_name].append(excuse) + return PolicyVerdict.PASS + + # We do know about linux-meta, so invalidate linux if meta is also + # invalid, otherwise leave it alone. + if not linux_meta_excuse.is_valid: + self.logger.info("Invalidating %s because %s is invalid", excuse.name, linux_meta_excuse.name) + res = PolicyVerdict.REJECTED_WAITING_FOR_ANOTHER_ITEM + uvname = linux_meta_excuse.uvname + excuse.add_verdict_info(res, "%s is not a candidate" % (uvname, uvname)) + return res + else: + self.logger.info("Not invalidating %s because %s is valid", excuse.name, linux_meta_excuse.name) + + return PolicyVerdict.PASS diff --git a/tests/test_autopkgtest.py b/tests/test_autopkgtest.py index bc14c60..33cc779 100644 --- a/tests/test_autopkgtest.py +++ b/tests/test_autopkgtest.py @@ -2078,6 +2078,59 @@ class AT(TestAutopkgtestBase): # everything from -meta self.assertEqual(exc['linux']['policy_info']['autopkgtest'], {'verdict': 'PASS'}) + def test_kernel_waits_on_meta(self): + '''linux waits on linux-meta''' + + self.data.add('dkms', False, {}) + self.data.add('dkms', True, {}) + self.data.add('fancy-dkms', False, {'Source': 'fancy', 'Depends': 'dkms (>= 1)'}, testsuite='autopkgtest-pkg-dkms') + self.data.add('fancy-dkms', True, {'Source': 'fancy', 'Depends': 'dkms (>= 1)'}, testsuite='autopkgtest-pkg-dkms') + self.data.add('linux-image-generic', False, {'Version': '0.1', 'Source': 'linux-meta', 'Depends': 'linux-image-1'}) + self.data.add('linux-image-1', False, {'Source': 'linux'}, testsuite='autopkgtest') + self.data.add('linux-firmware', False, {'Source': 'linux-firmware'}, testsuite='autopkgtest') + + self.swift.set_results({'autopkgtest-testing': { + 'testing/i386/f/fancy/20150101_090000@': (0, 'fancy 0.5', tr('passedbefore/1')), + 'testing/i386/l/linux/20150101_100000@': (0, 'linux 2', tr('linux-meta/0.2')), + 'testing/amd64/l/linux/20150101_100000@': (0, 'linux 2', tr('linux-meta/0.2')), + 'testing/i386/l/linux-firmware/20150101_100000@': (0, 'linux-firmware 2', tr('linux-firmware/2')), + 'testing/amd64/l/linux-firmware/20150101_100000@': (0, 'linux-firmware 2', tr('linux-firmware/2')), + }}) + + self.run_it( + [('linux-image-generic', {'Version': '0.2', 'Source': 'linux-meta', 'Depends': 'linux-image-2'}, None), + ('linux-image-2', {'Version': '2', 'Source': 'linux'}, 'autopkgtest'), + ('linux-firmware', {'Version': '2', 'Source': 'linux-firmware'}, 'autopkgtest'), + ], + {'linux-meta': (False, {'fancy': {'amd64': 'RUNNING-ALWAYSFAIL', 'i386': 'RUNNING'}, + 'linux/2': {'amd64': 'PASS', 'i386': 'PASS'} + }), + # no tests, but should wait on linux-meta + 'linux': (False, {}), + # this one does not have a -meta, so don't wait + 'linux-firmware': (True, {'linux-firmware/2': {'amd64': 'PASS', 'i386': 'PASS'}}), + }, + {'linux': [('excuses', 'linux-meta is not a candidate'), + ('dependencies', {'migrate-after': ['linux-meta']})] + } + ) + + # now linux-meta is ready to go + self.swift.set_results({'autopkgtest-testing': { + 'testing/i386/f/fancy/20150101_100000@': (0, 'fancy 1', tr('linux-meta/0.2')), + 'testing/amd64/f/fancy/20150101_100000@': (0, 'fancy 1', tr('linux-meta/0.2')), + }}) + self.run_it( + [], + {'linux-meta': (True, {'fancy/1': {'amd64': 'PASS', 'i386': 'PASS'}, + 'linux/2': {'amd64': 'PASS', 'i386': 'PASS'}}), + 'linux': (True, {}), + 'linux-firmware': (True, {'linux-firmware/2': {'amd64': 'PASS', 'i386': 'PASS'}}), + }, + {'linux': [('dependencies', {'migrate-after': ['linux-meta']})] + } + ) + ################################################################ # Tests for special-cased packages ################################################################