diff --git a/changelogs/fragments/dnf-ignore-weak-deps.yaml b/changelogs/fragments/dnf-ignore-weak-deps.yaml new file mode 100644 index 00000000000..f231950c3c5 --- /dev/null +++ b/changelogs/fragments/dnf-ignore-weak-deps.yaml @@ -0,0 +1,2 @@ +minor_changes: +- dnf - added the module option ``install_weak_deps`` to control whether DNF will install weak dependencies diff --git a/lib/ansible/module_utils/yumdnf.py b/lib/ansible/module_utils/yumdnf.py index 7f5e5500931..3aaa335ae5c 100644 --- a/lib/ansible/module_utils/yumdnf.py +++ b/lib/ansible/module_utils/yumdnf.py @@ -34,6 +34,7 @@ yumdnf_argument_spec = dict( exclude=dict(type='list', default=[]), installroot=dict(type='str', default="/"), install_repoquery=dict(type='bool', default=True), + install_weak_deps=dict(type='bool', default=True), list=dict(type='str'), name=dict(type='list', aliases=['pkg'], default=[]), releasever=dict(default=None), @@ -77,6 +78,7 @@ class YumDnf(with_metaclass(ABCMeta, object)): self.exclude = self.module.params['exclude'] self.installroot = self.module.params['installroot'] self.install_repoquery = self.module.params['install_repoquery'] + self.install_weak_deps = self.module.params['install_weak_deps'] self.list = self.module.params['list'] self.names = [p.strip() for p in self.module.params['name']] self.releasever = self.module.params['releasever'] diff --git a/lib/ansible/modules/packaging/os/dnf.py b/lib/ansible/modules/packaging/os/dnf.py index 142566263a6..67ca827c68d 100644 --- a/lib/ansible/modules/packaging/os/dnf.py +++ b/lib/ansible/modules/packaging/os/dnf.py @@ -184,6 +184,12 @@ options: default: 0 type: int version_added: "2.8" + install_weak_deps: + description: + - Will also install all packages linked by a weak dependency relation. + type: bool + default: "yes" + version_added: "2.8" notes: - When used with a `loop:` each package will be processed individually, it is much more efficient to pass the list directly to the `name` option. - Group removal doesn't work if the group was installed with Ansible because @@ -559,6 +565,9 @@ class DnfModule(YumDnf): # Default in dnf upstream is true conf.clean_requirements_on_remove = self.autoremove + # Default in dnf (and module default) is True + conf.install_weak_deps = self.install_weak_deps + def _specify_repositories(self, base, disablerepo, enablerepo): """Enable and disable repositories matching the provided patterns.""" base.read_all_repos() diff --git a/lib/ansible/modules/packaging/os/yum.py b/lib/ansible/modules/packaging/os/yum.py index 12185dc2ac9..f9c2c119347 100644 --- a/lib/ansible/modules/packaging/os/yum.py +++ b/lib/ansible/modules/packaging/os/yum.py @@ -190,6 +190,13 @@ options: default: 0 type: int version_added: "2.8" + install_weak_deps: + description: + - Will also install all packages linked by a weak dependency relation. + - "NOTE: This feature requires yum >= 4 (RHEL/CentOS 8+)" + type: bool + default: "yes" + version_added: "2.8" notes: - When used with a `loop:` each package will be processed individually, it is much more efficient to pass the list directly to the `name` option. diff --git a/test/integration/targets/dnf/tasks/repo.yml b/test/integration/targets/dnf/tasks/repo.yml index 874ade75e7f..89aa87462a8 100644 --- a/test/integration/targets/dnf/tasks/repo.yml +++ b/test/integration/targets/dnf/tasks/repo.yml @@ -208,8 +208,59 @@ - "not dnf_result.changed" - "dnf_result is failed" # ============================================================================ + + # Should install foo-with-weak-dep and foo-weak-dep + - name: Install package with defaults + dnf: + name: foo-with-weak-dep + state: present + + - name: Check if foo-with-weak-dep is installed + shell: rpm -q foo-with-weak-dep + register: rpm_main_result + + - name: Check if foo-weak-dep is installed + shell: rpm -q foo-weak-dep + register: rpm_weak_result + + - name: Verify install with weak deps + assert: + that: + - rpm_main_result.rc == 0 + - rpm_weak_result.rc == 0 + + - name: Uninstall foo weak dep packages + dnf: + name: + - foo-with-weak-dep + - foo-weak-dep + state: absent + + - name: Install package with weak deps but skip weak deps + dnf: + name: foo-with-weak-dep + install_weak_deps: False + state: present + + - name: Check if foo-with-weak-dep is installed + shell: rpm -q foo-with-weak-dep + register: rpm_main_result + + - name: Check if foo-weak-dep is installed + shell: rpm -q foo-weak-dep + register: rpm_weak_result + ignore_errors: yes + + - name: Verify install without weak deps + assert: + that: + - rpm_main_result.rc == 0 + - rpm_weak_result.rc == 1 # the weak dependency shouldn't be installed always: - name: Clean up dnf: - name: foo + name: + - foo + - foo-with-weak-dep + - foo-weak-dep state: absent diff --git a/test/integration/targets/setup_mysql_db/tasks/main.yml b/test/integration/targets/setup_mysql_db/tasks/main.yml index ee7e03872db..5d4ae3c8df5 100644 --- a/test/integration/targets/setup_mysql_db/tasks/main.yml +++ b/test/integration/targets/setup_mysql_db/tasks/main.yml @@ -43,28 +43,12 @@ with_items: "{{mysql_packages}}" when: ansible_pkg_mgr == 'yum' -- block: - # This is required as mariadb-server has a weak dependency on Python 2 which causes the test to break on Py3 hosts - - name: create test dnf.conf file to ignore weak dependencies - copy: - content: | - [main] - install_weak_deps=False - dest: '{{ output_dir }}/dnf.conf' - register: test_dnf_conf_copy - - - name: install mysqldb_test rpm dependencies - dnf: - name: '{{ item }}' - state: latest - conf_file: '{{ test_dnf_conf_copy.dest }}' - with_items: "{{mysql_packages}}" - - always: - - name: remove test dnf.conf file - file: - path: '{{ test_dnf_conf_copy.dest }}' - state: absent +- name: install mysqldb_test rpm dependencies + dnf: + name: '{{ item }}' + state: latest + install_weak_deps: False # mariadb-server has a weak dep on python2 which break Python 3 test environments + with_items: "{{mysql_packages}}" when: ansible_pkg_mgr == 'dnf' - name: install mysqldb_test debian dependencies diff --git a/test/integration/targets/setup_rpm_repo/files/create-repo.py b/test/integration/targets/setup_rpm_repo/files/create-repo.py index bf5cf5440a6..0d9c0be9ef4 100644 --- a/test/integration/targets/setup_rpm_repo/files/create-repo.py +++ b/test/integration/targets/setup_rpm_repo/files/create-repo.py @@ -6,17 +6,19 @@ from collections import namedtuple import rpmfluff -RPM = namedtuple('RPM', ['name', 'version', 'release', 'epoch']) +RPM = namedtuple('RPM', ['name', 'version', 'release', 'epoch', 'recommends']) SPECS = [ - RPM('foo', '1.0', '1', None), - RPM('foo', '1.0', '2', '1'), - RPM('foo', '1.1', '1', '1'), - RPM('foo-bar', '1.0', '1', None), - RPM('foo-bar', '1.1', '1', None), - RPM('bar', '1.0', '1', None), - RPM('bar', '1.1', '1', None), + RPM('foo', '1.0', '1', None, None), + RPM('foo', '1.0', '2', '1', None), + RPM('foo', '1.1', '1', '1', None), + RPM('foo-bar', '1.0', '1', None, None), + RPM('foo-bar', '1.1', '1', None, None), + RPM('bar', '1.0', '1', None, None), + RPM('bar', '1.1', '1', None, None), + RPM('foo-with-weak-dep', '1.0', '1', None, ['foo-weak-dep']), + RPM('foo-weak-dep', '1.0', '1', None, None), ] @@ -30,6 +32,15 @@ def main(): for spec in SPECS: pkg = rpmfluff.SimpleRpmBuild(spec.name, spec.version, spec.release, [arch]) pkg.epoch = spec.epoch + + if spec.recommends: + # Skip packages that require weak deps but an older version of RPM is being used + if not hasattr(rpmfluff, "can_use_rpm_weak_deps") or not rpmfluff.can_use_rpm_weak_deps(): + continue + + for recommend in spec.recommends: + pkg.add_recommends(recommend) + pkgs.append(pkg) repo = rpmfluff.YumRepoBuild(pkgs)