Bug 1465734 - rpmdeplint does not find conflicts between different versions of installonly packages (such as kernel)
rpmdeplint does not find conflicts between different versions of installonly ...
Product: rpmdeplint
Classification: Community
Component: general (Show other bugs)
Unspecified Unspecified
unspecified Severity unspecified (vote)
: 2.0
: ---
Assigned To: Dan Callaghan
Depends On:
  Show dependency treegraph
Reported: 2017-06-28 00:56 EDT by Dan Callaghan
Modified: 2017-08-14 00:18 EDT (History)
5 users (show)

See Also:
Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
Last Closed:
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)

  None (edit)
Description Dan Callaghan 2017-06-28 00:56:34 EDT
The kernel package (and in newer Fedora releases, kernel-core kernel-modules kernel-devel etc) is treated specially by yum and dnf, with its so-called "installonly" feature. When upgrading, instead of replacing the older version, the new version is installed in parallel with the old version (hence "install only" because they are never upgraded only installed).

This special case impacts rpmdeplint's check to find file conflicts.

For a normal package, it doesn't matter if glibc-1 and glibc-2 both contain the same file with different contains (indeed, it is very much expected) because glibc-2 will replace glibc-1. So rpmdeplint won't report any problem for this case.

However if kernel-1 and kernel-2 both contain the same file with different contents this *is* an error, because they can be installed at the same time. The kernel packages are carefully designed to be parallel installable by putting everything into versioned directories but if something goes wrong with this, rpmdeplint should find the problem.

Right now rpmdeplint does not do any special handling for installonly packages, it treats them like regular packages which means it will not find conflicts between different versions of installonly packages.

Version-Release number of selected component (if applicable):

How reproducible:
easily with the test suite, not so easily if you try to build a real kernel

Steps to Reproduce:
1. Make two kernel packages which both contain the same file with different contents
2. Put one in a repo
3. Run rpmdeplint check-conflicts against that repo and the other kernel package

Actual results:
No problems found

Expected results:
Should report the conflicting file
Comment 1 Dan Callaghan 2017-06-28 01:15:06 EDT
I did a bit of research to get to the bottom of how this works in libsolv, dnf, and yum...

At the libsolv level, this magic:

(In reply to Dan Callaghan from comment #0)
> For a normal package, it doesn't matter if glibc-1 and glibc-2 both contain
> the same file with different contains (indeed, it is very much expected)
> because glibc-2 will replace glibc-1.

is called "implicit obsoletes". That is, when you ask libsolv to install glibc-2 it implicitly obsoletes any other package with the same name. That causes glibc-1 to be replaced by glibc-2.

The notion of "installonly" packages is purely at the yum/dnf level. Both yum and dnf have a config option to control the list of package names which are considered to be installonly, with the default list growing over the years but basically just covering the kernel.

Specifically yum/config.py has the following defaults:

 650     installonlypkgs = ListOption(['kernel', 'kernel-bigmem',
 651             'kernel-enterprise','kernel-smp', 'kernel-modules', 'kernel-debug',
 652             'kernel-unsupported', 'kernel-source', 'kernel-devel', 'kernel-PAE',
 653             'kernel-PAE-debug'])

whereas latest dnf/const.py.in has the following defaults:

 28 INSTALLONLYPKGS=['kernel', 'kernel-PAE',
 29                  'installonlypkg(kernel)',
 30                  'installonlypkg(kernel-module)',
 31                  'installonlypkg(vm)']

The installonlypkg(*) names are virtual provides which the current Fedora kernel-core and kernel-modules packages provide, so this is the "modern" way to signal to dnf that a package is installonly.

Presumably whoever invented the installonlypkg(*) virtual was intending that dnf would honour ANY value inside the brackets, but for whatever reason dnf only matches on those three particular strings.

But anyway... In dnf the list of installonly packages from the config is passed down and set on the sack, and eventually ends up at the following code in construct_job() of hy-goal.c:

 340     /* turn off implicit obsoletes for installonly packages */
 341     for (int i = 0; i < (int) dnf_sack_get_installonly(sack)->count; i++)
 343                     dnf_sack_get_installonly(sack)->elements[i]);

The SOLVER_MULTIVERSION action is what turns off the implicit obsoletes. According to libsolv-bindings.txt:

  Mark the matched packages for multiversion install. If they get to be
  installed because of some other job, the installation will keep the old
  version of the package installed (for rpm this is done by using ``-i''
  instead of ``-U'').

And the SOLVER_SOLVABLE_PROVIDES flag is because dnf wants to match the installonlypkgs against virtual provides like installonlypkg(kernel) not just literal package names.
Comment 2 Dan Callaghan 2017-06-28 01:24:26 EDT
As far as how to handle this in rpmdeplint...

In the conflict checking code, when we check if two packages can be installed together, we will need to add a job/goal to account for installonly packages, so that we correctly identify that two kernel packages *can* be installed together and therefore should *not* skip conflict checking.

The fact that the set of installonly packages is actually configurable per system makes things difficult. It means we can't in general know whether any given package would be treated as installonly. But realistically, an end user cannot just blindly configure arbitrary packages to be installonly (for example if I set glibc installonly it just won't work because of the conflicts).

Presumably the only reason this is configurable by end users is just to cover the case where the user has some package kernel-frobnoz from some third-party repository that they want to be treated *like* the kernel. In the old days of yum, manually adding kernel-frobnoz to installonlypkgs in yum.conf would have been the only way to make that work. The modern answer would be that kernel-frobnoz should add a virtual provide for installonlypkg(kernel) and then dnf will know to handle it correctly.

So for rpmdeplint's purposes, we could just hardcode the union of all installonlypkgs that have been defined in dnf and yum (basically, all those variations of kernel-* plus the installonlypkg(*) virtuals).

For completeness we could also add a command-line option --installonlypkgs=...,... to let the caller configure a different set, in case they are testing some third-party repo which has a kernel-like package. And maybe also --installonlypkgs-from-system to make it read the list from /etc/yum.conf, like the --repos-from-system option that we have.
Comment 3 Dan Callaghan 2017-06-29 21:09:48 EDT

I didn't add any --installonlypkgs option for configuring the set of installonly packages, because I don't think it's really necessary.

Note You need to log in before you can comment on or make changes to this bug.