Bug 1700741 - When dnf plugin is upgraded via Obsolete, it is not run in the transaction phase
Summary: When dnf plugin is upgraded via Obsolete, it is not run in the transaction phase
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 8
Classification: Red Hat
Component: dnf
Version: 8.0
Hardware: Unspecified
OS: Unspecified
low
unspecified
Target Milestone: rc
: 8.0
Assignee: Jaroslav Mracek
QA Contact: Karel Srot
URL:
Whiteboard:
Depends On: 1681084
Blocks:
TreeView+ depends on / blocked
 
Reported: 2019-04-17 09:54 UTC by Jan Pazdziora
Modified: 2020-11-14 08:02 UTC (History)
4 users (show)

Fixed In Version: dnf-4.2.7-3.el8
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2019-11-05 22:21:49 UTC
Type: Bug
Target Upstream Version:


Attachments (Terms of Use)


Links
System ID Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2019:3583 None None None 2019-11-05 22:22:01 UTC

Description Jan Pazdziora 2019-04-17 09:54:56 UTC
Description of problem:

When dnf plugin is shipped via rpm package and that rpm package gets upgraded to newer version, the operation of the plugin is not disturbed -- the transaction() call after the old package was removed is still invoked, running code from the old version.

However, when instead of upgrading the rpm package with the plugin, different package which brings the same dnf plugin is installed, and it removes the previous package via Obsoletes, the transaction() is not invoked.

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

dnf-4.0.9.2-5.el8.noarch

How reproducible:

Deterministic.

Steps to Reproduce:
1. Have plugin code in dnf-plugins/a.py which implements plugin "a" which will show us the list of installed and removed packages:

from dnf import Plugin
from dnfpluginscore import logger

class a(Plugin):

	def resolved(self):
		logger.warning("resolved a0: install_set %s, remove_set %s"
			% ( self.base.transaction.install_set, self.base.transaction.remove_set ))

	def transaction(self):
		logger.warning("transaction a0: install_set %s, remove_set %s"
			% ( self.base.transaction.install_set, self.base.transaction.remove_set ))

2. Have setup.py:

try:
	from setuptools import setup
except ImportError:
	from distutils.core import setup

setup(
	name = 'a-plugin',
	version = '0.0.0',
	py_modules = ['dnf-plugins.a'],
)

3. Build the plugin rpm: python3 setup.py bdist_rpm --binary-only
4. Install the plugin: dnf install -y dist/a-plugin-0.0.0-1.noarch.rpm
5. Install some package, to see what the transaction looks like:
   dnf install -y zsh
6. Observe the output says

Last metadata expiration check: 0:59:09 ago on Wed 17 Apr 2019 04:34:58 AM EDT.
resolved a0: install_set {<hawkey.Package object id 13644, zsh-5.5.1-6.el8.x86_64, BaseOS>}, remove_set set()
Dependencies resolved.
[...]
  Verifying        : zsh-5.5.1-6.el8.x86_64                                 1/1 
Installed products updated.
transaction a0: install_set {<hawkey.Package object id 13644, zsh-5.5.1-6.el8.x86_64, BaseOS>}, remove_set set()

7. Now we update the version of the rpm but also record the new version in the plugin code:

diff --git a/dnf-plugins/a.py b/dnf-plugins/a.py
index 8467b0f..a5da385 100644
--- a/dnf-plugins/a.py
+++ b/dnf-plugins/a.py
@@ -4,9 +4,9 @@ from dnfpluginscore import logger
 class a(Plugin):
 
        def resolved(self):
-               logger.warning("resolved a0: install_set %s, remove_set %s"
+               logger.warning("resolved a1: install_set %s, remove_set %s"
                        % ( self.base.transaction.install_set, self.base.transaction.remove_set ))
 
        def transaction(self):
-               logger.warning("transaction a0: install_set %s, remove_set %s"
+               logger.warning("transaction a1: install_set %s, remove_set %s"
                        % ( self.base.transaction.install_set, self.base.transaction.remove_set ))
diff --git a/setup.py b/setup.py
index 01d7eb4..98b370b 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ except ImportError:
 
 setup(
        name = 'a-plugin',
-       version = '0.0.0',
+       version = '1.0.0',
        py_modules = ['dnf-plugins.a'],
 )

8. Build rpm: python3 setup.py bdist_rpm --binary-only
9. Upgrade the plugin: dnf upgrade -y dist/a-plugin-1.0.0-1.noarch.rpm 
10. Observe the output says that the old version (a0) code was invoked both before the upgrade (resolved) and after the upgrade (transaction):

resolved a0: install_set {<hawkey.Package object id 46307, a-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-0.0.0-1.noarch, @System>}
[...]
Installed products updated.
transaction a0: install_set {<hawkey.Package object id 46307, a-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-0.0.0-1.noarch, @System>}

11. Run some dnf operation and notice that now the "a1" code is invoked:
    dnf remove -y zsh

resolved a1: install_set set(), remove_set {<hawkey.Package object id 444, zsh-5.5.1-6.el8.x86_64, @System>}
[...]
transaction a1: install_set set(), remove_set {<hawkey.Package object id 444, zsh-5.5.1-6.el8.x86_64, @System>}

12. Now move the plugin to different rpm package, from a-plugin to b-plugin. Since the actual name of the plugin and thus the file where it is stored stays the same, we need to add Obsoletes, to avoid errors like file /usr/lib/python3.6/site-packages/dnf-plugins/a.py from install of b-plugin-1.0.0-1.noarch conflicts with file from package a-plugin-1.0.0-1.noarch:

  diff --git a/dnf-plugins/a.py b/dnf-plugins/a.py
index a5da385..22a1b9e 100644
--- a/dnf-plugins/a.py
+++ b/dnf-plugins/a.py
@@ -4,9 +4,9 @@ from dnfpluginscore import logger
 class a(Plugin):
 
        def resolved(self):
-               logger.warning("resolved a1: install_set %s, remove_set %s"
+               logger.warning("resolved b1: install_set %s, remove_set %s"
                        % ( self.base.transaction.install_set, self.base.transaction.remove_set ))
 
        def transaction(self):
-               logger.warning("transaction a1: install_set %s, remove_set %s"
+               logger.warning("transaction b1: install_set %s, remove_set %s"
                        % ( self.base.transaction.install_set, self.base.transaction.remove_set ))
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..0b08475
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_rpm]
+obsoletes = a-plugin
diff --git a/setup.py b/setup.py
index 98b370b..4937d84 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ except ImportError:
        from distutils.core import setup
 
 setup(
-       name = 'a-plugin',
+       name = 'b-plugin',
        version = '1.0.0',
        py_modules = ['dnf-plugins.a'],
 )

13. Build rpm: python3 setup.py bdist_rpm --binary-only
14. Install the new package: dnf install -y dist/b-plugin-1.0.0-1.noarch.rpm

Actual results:

Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 0:11:35 ago on Wed 17 Apr 2019 05:36:48 AM EDT.
resolved a1: install_set {<hawkey.Package object id 46306, b-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-1.0.0-1.noarch, @System>}
Dependencies resolved.
================================================================================
 Package           Arch            Version          Repository             Size
================================================================================
Installing:
 b-plugin          noarch          1.0.0-1          @commandline          8.2 k
     replacing  a-plugin.noarch 1.0.0-1

Transaction Summary
================================================================================
Install  1 Package

Total size: 8.2 k
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Installing       : b-plugin-1.0.0-1.noarch                                1/2 
  Obsoleting       : a-plugin-1.0.0-1.noarch                                2/2 
  Running scriptlet: a-plugin-1.0.0-1.noarch                                2/2 
  Verifying        : b-plugin-1.0.0-1.noarch                                1/2 
  Verifying        : a-plugin-1.0.0-1.noarch                                2/2 
Installed products updated.

Installed:
  b-plugin-1.0.0-1.noarch                                                       

Complete!

Expected results:

Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Last metadata expiration check: 0:11:35 ago on Wed 17 Apr 2019 05:36:48 AM EDT.
resolved a1: install_set {<hawkey.Package object id 46306, b-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-1.0.0-1.noarch, @System>}
Dependencies resolved.
================================================================================
 Package           Arch            Version          Repository             Size
================================================================================
Installing:
 b-plugin          noarch          1.0.0-1          @commandline          8.2 k
     replacing  a-plugin.noarch 1.0.0-1

Transaction Summary
================================================================================
Install  1 Package

Total size: 8.2 k
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Installing       : b-plugin-1.0.0-1.noarch                                1/2 
  Obsoleting       : a-plugin-1.0.0-1.noarch                                2/2 
  Running scriptlet: a-plugin-1.0.0-1.noarch                                2/2 
  Verifying        : b-plugin-1.0.0-1.noarch                                1/2 
  Verifying        : a-plugin-1.0.0-1.noarch                                2/2 
Installed products updated.
transaction a1: install_set {<hawkey.Package object id 46306, b-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-1.0.0-1.noarch, @System>}

Installed:
  b-plugin-1.0.0-1.noarch                                                       

Complete!

In other words, I expect the transaction phase of the original (a-plugin-1.0.0-1) to be still invoked, and the

transaction a1: install_set {<hawkey.Package object id 46306, b-plugin-1.0.0-1.noarch, @commandline>}, remove_set {<hawkey.Package object id 6, a-plugin-1.0.0-1.noarch, @System>}

output to be shown.

Additional info:

Comment 2 Jaroslav Mracek 2019-07-03 17:03:16 UTC
I would like to resolve the issue by enhancing a documentation. Please do you have any suggestion where to put such information?

Comment 3 Jan Pazdziora 2019-07-08 09:35:34 UTC
I'd likely put it to the dnf plugin API documentation, as a note about behaviour expectations.

Comment 4 Jaroslav Mracek 2019-07-22 07:40:38 UTC
I added a note for the transaction hook into documentation: https://github.com/rpm-software-management/dnf/pull/1435

Comment 9 errata-xmlrpc 2019-11-05 22:21:49 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2019:3583


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