-
Notifications
You must be signed in to change notification settings - Fork 26
[ART-3965] A new mechanism to detect rpm changes in stream builds #798
[ART-3965] A new mechanism to detect rpm changes in stream builds #798
Conversation
acfe933
to
effa5d0
Compare
effa5d0
to
ea946ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lots of helpful comments in here, great. would be nice to see the comments from the PR description included in the code
could you update the validator to accept exempted_packages
?
just a few nits you can likely ignore, otherwise lgtm
doozerlib/cli/scan_sources.py
Outdated
@@ -109,6 +110,7 @@ def add_image_meta_change(meta, rebuild_hint: RebuildHint): | |||
oldest_image_event_ts = None | |||
newest_image_event_ts = 0 | |||
for image_meta in runtime.image_metas(): | |||
dgk = image_meta.distgit_key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appears nothing uses this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dkg
is used in line 167 and 170 for logging but we forgot to define it within the loop.
Maybe adding this variable here is not obvious because the actual use is far away from this line.
I will remove this and open another PR for the fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels like there had to be an existing module that already does all this, but i haven't actually looked for one! oh, well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed there are existing modules to read the content of primary.xml.gz, but didn't find anything for modules.yaml.gz. Fortunately it is not hard to parse those content so decided to do it by myself (also as a learning experience)
doozerlib/repodata.py
Outdated
|
||
|
||
class OutdatedRPMFinder: | ||
async def find_non_latest_rpms(self, rpms_to_check: List[Dict], repodatas: List[Repodata], logger: Optional[Logger] = None) -> List[Tuple[str, str, str]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looong method. looks like it would be easy to break up into smaller testable methods?... i mean you managed to test it anyway, just seems like it would've been cleaner broken out.
@@ -188,72 +192,26 @@ def conf_section(self, repotype, arch=ARCH_X86_64, enabled=None, section_name=No | |||
|
|||
return result | |||
|
|||
# Map arch to compatible arches |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so much being removed! 🤩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah repoquery command needs them otherwise it will not list all supported arches. It is not needed any more since because this PR reads repodata directly.
This is to support openshift-eng/doozer#798.
This is to support openshift-eng/doozer#798.
Currently we use a tag based approach to detect rpm changes in stream builds. It considers a package X is outdated if a newer version Y is tagged into any of X's tags. This approach has some limitations. Especially, it can't detect rpm changes after RHEL version moves or the image moves to a different repo (see https://issues.redhat.com/browse/ART-3965 for a real problem). I will give you an example to show how it fails to detect a change: - Image A enables a RHEL 8.4 repo. - Package `foo-1.0.0-1.el8_3.x86_64.rpm` is installed in image A. It has `rhel-8.3.0-z` tag in Brew. - A newer version `foo-1.1.0-1.el8_4.x86_64.rpm` is released and has `rhel-8.4.0-z` tag. - Doozer doesn't think `foo-1.0.0-1.el8_3.x86_64.rpm` is outdated because the newer version `foo-1.1.0-1.el8_4.x86_64.rpm` doesn't have `rhel-8.3.0-z` tag. To address this limitation, a new approach is proposed to actually query the content of all enabled repos and compare the installed versions with the latest versions in repos. I will call it "content based" approach. This content based approach has been proved in `gen-payload` command (invoked in `build-sync` job) with the merge of openshift-eng#764. If you look at [the logs of build-sync build](https://saml.buildvm.hosts.prod.psi.bos.redhat.com:8888/job/aos-cd-builds/job/build%252Fbuild-sync/34458/consoleFull), you will see it shows you which images contain outdated rpms. It contains entries like: ```yaml - code: OUTDATED_RPMS_IN_STREAM_BUILD msg: Found outdated RPM (perl-Pod-Perldoc-3.28-396.el8) installed in openshift-enterprise-builder-container-v4.14.0-202307111728.p0.gfe78ee6.assembly.stream (x86_64) when perl-Pod-Perldoc-3.28.01-443.module+el8.6.0+13324+628a2397 was available in repo rhel-8-appstream-rpms ``` However, the above example is actually a false positive. It is because package `perl-Pod-Perldoc-3.28-396.el8` comes from a modular repo but our code is not module-aware. A modular rpm repo provides multiple upgrade paths. We should only consider a newer version is upgradable if it belongs to the same stream. For more information about modules, see https://docs.fedoraproject.org/en-US/modularity/. That is a major reason why this new approach is adopted to `scan-sources`, otherwise it would constantly trigger unnecessary rebuilds! This PR not only updates `scan-sources` to use the new approach, but only adds module-awareness to eliminate false positives. The new algorithm (probably oversimplified): 1. For an image build, get all modular rpms in enabled repos. 2. For each installed rpm, check if the rpm is contained by a module. 3. If yes, we will consider that module stream is "enabled" for this image. 4. For each enabled module stream, find the module with the largest version. 5. Collect all modular rpms from those modules as collection M. 6. Collect all non-modular rpms with the latest version as collection N. If the package name of a non-modular rpm is already included in the modular rpms collection, exclude it. 7. For each installed rpm, check if it is a modular rpm or not. If it is modular, check if it is older than the one in collection M. Otherwise, check if it is older than the one in collection N. 8. If it is older, we consider is it an outdated rpm. Note: 1. There is no Brew API or any other cheap way to precisely determine which module streams are enabled during an image build. The method used in the above algorithm is actually *guess*. It is not perfect, but my tests conclude it is good enough for our use cases (probably because we don't use a lot of modular rpms in our images). 2. Some images use pins in their Dockerfiles. We should exempt them from scan-sources. The exemption can be defined in ocp-build-data image metadata. e.g. ```yaml scan_sources: exempted_packages: - openvswitch3.1 - python3-openvswitch3.1 ```
ea946ae
to
17cc8b6
Compare
Build #7
|
@sosiouxme Thank you so much for the review! I've addressed your review suggestions in the latest commit. |
Build #8
|
This is to support openshift-eng/doozer#798.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
Currently we use a tag based approach to detect rpm changes in stream builds. It considers a package X is outdated if a newer version Y is tagged into any of X's tags. This approach has some limitations. Especially, it can't detect rpm changes after RHEL version moves or the image moves to a different repo (see https://issues.redhat.com/browse/ART-3965 for a real problem).
I will give you an example to show how it fails to detect a change:
foo-1.0.0-1.el8_3.x86_64.rpm
is installed in image A. It hasrhel-8.3.0-z
tag in Brew.foo-1.1.0-1.el8_4.x86_64.rpm
is released and hasrhel-8.4.0-z
tag.foo-1.0.0-1.el8_3.x86_64.rpm
is outdated because the newer versionfoo-1.1.0-1.el8_4.x86_64.rpm
doesn't haverhel-8.3.0-z
tag.To address this limitation, a new approach is proposed to actually query the content of all enabled repos and compare the installed versions with the latest versions in repos. I will call it "content based" approach.
This content based approach has been proved in
gen-payload
command (invoked inbuild-sync
job) with the merge of #764. If you look at the logs of build-sync build, you will see it shows you which images contain outdated rpms. It contains entries like:However, the above example is actually a false positive. It is because package
perl-Pod-Perldoc-3.28-396.el8
comes from a modular repo but our code is not module-aware. A modular rpm repo provides multiple upgrade paths. We should only consider a newer version is upgradable if it belongs to the same stream. For more information about modules, see https://docs.fedoraproject.org/en-US/modularity/. That is a major reason why this new approach is adopted toscan-sources
, otherwise it would constantly trigger unnecessary rebuilds!This PR not only updates
scan-sources
to use the new approach, but only adds module-awareness to eliminate false positives. The new algorithm (probably oversimplified):Note: