Skip to content

Commit

Permalink
Update pkg.group_installed state to support repo options
Browse files Browse the repository at this point in the history
  • Loading branch information
terminalmage authored and garethgreenaway committed Aug 16, 2023
1 parent 8dfe5e8 commit 3e73ae4
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 17 deletions.
69 changes: 64 additions & 5 deletions salt/modules/yumpkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def _yum_pkginfo(output):
keys = itertools.cycle(("name", "version", "repoid"))
values = salt.utils.itertools.split(_strip_headers(output))
osarch = __grains__["osarch"]
for (key, value) in zip(keys, values):
for key, value in zip(keys, values):
if key == "name":
try:
cur["name"], cur["arch"] = value.rsplit(".", 1)
Expand Down Expand Up @@ -2570,7 +2570,7 @@ def group_list():
return ret


def group_info(name, expand=False, ignore_groups=None):
def group_info(name, expand=False, ignore_groups=None, **kwargs):
"""
.. versionadded:: 2014.1.0
.. versionchanged:: 2015.5.10,2015.8.4,2016.3.0,3001
Expand All @@ -2581,6 +2581,10 @@ def group_info(name, expand=False, ignore_groups=None):
to ``mandatory``, ``optional``, and ``default`` for accuracy, as
environment groups include other groups, and not packages. Finally,
this function now properly identifies conditional packages.
.. versionchanged:: 3006.2
Support for ``fromrepo``, ``enablerepo``, and ``disablerepo`` (as used
in :py:func:`pkg.install <salt.modules.yumpkg.install>`) has been
added.
Lists packages belonging to a certain group
Expand All @@ -2601,18 +2605,46 @@ def group_info(name, expand=False, ignore_groups=None):
.. versionadded:: 3001
fromrepo
Restrict ``yum groupinfo`` to the specified repo(s).
(e.g., ``yum --disablerepo='*' --enablerepo='somerepo'``)
.. versionadded:: 3006.2
enablerepo (ignored if ``fromrepo`` is specified)
Specify a disabled package repository (or repositories) to enable.
(e.g., ``yum --enablerepo='somerepo'``)
.. versionadded:: 3006.2
disablerepo (ignored if ``fromrepo`` is specified)
Specify an enabled package repository (or repositories) to disable.
(e.g., ``yum --disablerepo='somerepo'``)
.. versionadded:: 3006.2
CLI Example:
.. code-block:: bash
salt '*' pkg.group_info 'Perl Support'
salt '*' pkg.group_info 'Perl Support' fromrepo=base,updates
salt '*' pkg.group_info 'Perl Support' enablerepo=somerepo
"""
pkgtypes = ("mandatory", "optional", "default", "conditional")
ret = {}
for pkgtype in pkgtypes:
ret[pkgtype] = set()

cmd = [_yum(), "--quiet", "groupinfo", name]
options = _get_options(
**{
key: val
for key, val in kwargs.items()
if key in ("fromrepo", "enablerepo", "disablerepo")
}
)

cmd = [_yum(), "--quiet"] + options + ["groupinfo", name]
out = __salt__["cmd.run_stdout"](cmd, output_loglevel="trace", python_shell=False)

g_info = {}
Expand Down Expand Up @@ -2680,30 +2712,57 @@ def group_info(name, expand=False, ignore_groups=None):
return ret


def group_diff(name):
def group_diff(name, **kwargs):
"""
.. versionadded:: 2014.1.0
.. versionchanged:: 2015.5.10,2015.8.4,2016.3.0
Environment groups are now supported. The key names have been renamed,
similar to the changes made in :py:func:`pkg.group_info
<salt.modules.yumpkg.group_info>`.
.. versionchanged:: 3006.2
Support for ``fromrepo``, ``enablerepo``, and ``disablerepo`` (as used
in :py:func:`pkg.install <salt.modules.yumpkg.install>`) has been
added.
Lists which of a group's packages are installed and which are not
installed
name
The name of the group to check
fromrepo
Restrict ``yum groupinfo`` to the specified repo(s).
(e.g., ``yum --disablerepo='*' --enablerepo='somerepo'``)
.. versionadded:: 3006.2
enablerepo (ignored if ``fromrepo`` is specified)
Specify a disabled package repository (or repositories) to enable.
(e.g., ``yum --enablerepo='somerepo'``)
.. versionadded:: 3006.2
disablerepo (ignored if ``fromrepo`` is specified)
Specify an enabled package repository (or repositories) to disable.
(e.g., ``yum --disablerepo='somerepo'``)
.. versionadded:: 3006.2
CLI Example:
.. code-block:: bash
salt '*' pkg.group_diff 'Perl Support'
salt '*' pkg.group_diff 'Perl Support' fromrepo=base,updates
salt '*' pkg.group_diff 'Perl Support' enablerepo=somerepo
"""
pkgtypes = ("mandatory", "optional", "default", "conditional")
ret = {}
for pkgtype in pkgtypes:
ret[pkgtype] = {"installed": [], "not installed": []}

pkgs = list_pkgs()
group_pkgs = group_info(name, expand=True)
group_pkgs = group_info(name, expand=True, **kwargs)
for pkgtype in pkgtypes:
for member in group_pkgs.get(pkgtype, []):
if member in pkgs:
Expand Down
50 changes: 46 additions & 4 deletions salt/states/pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2940,7 +2940,6 @@ def _uninstall(
}

if __opts__["test"]:

_changes = {}
_changes.update({x: {"new": "{}d".format(action), "old": ""} for x in targets})

Expand Down Expand Up @@ -3306,9 +3305,16 @@ def group_installed(name, skip=None, include=None, **kwargs):
.. versionchanged:: 2016.11.0
Added support in :mod:`pacman <salt.modules.pacman>`
.. versionchanged:: 3006.2
For RPM-based systems, support for ``fromrepo``, ``enablerepo``, and
``disablerepo`` (as used in :py:func:`pkg.install
<salt.modules.yumpkg.install>`) has been added. This allows one to, for
example, use ``enablerepo`` to perform a group install from a repo that
is otherwise disabled.
Ensure that an entire package group is installed. This state is currently
only supported for the :mod:`yum <salt.modules.yumpkg>` and :mod:`pacman <salt.modules.pacman>`
package managers.
only supported for the :mod:`yum <salt.modules.yumpkg>` and :mod:`pacman
<salt.modules.pacman>` package managers.
skip
Packages that would normally be installed by the package group
Expand Down Expand Up @@ -3338,6 +3344,42 @@ def group_installed(name, skip=None, include=None, **kwargs):
This option can no longer be passed as a comma-separated list, it
must now be passed as a list (as shown in the above example).
fromrepo
Restrict ``yum groupinfo`` to the specified repo(s).
(e.g., ``yum --disablerepo='*' --enablerepo='somerepo'``)
.. code-block:: yaml
MyGroup:
pkg.group_installed:
- fromrepo: base,updates
.. versionadded:: 3006.2
enablerepo (ignored if ``fromrepo`` is specified)
Specify a disabled package repository (or repositories) to enable.
(e.g., ``yum --enablerepo='somerepo'``)
.. code-block:: yaml
MyGroup:
pkg.group_installed:
- enablerepo: myrepo
.. versionadded:: 3006.2
disablerepo (ignored if ``fromrepo`` is specified)
Specify an enabled package repository (or repositories) to disable.
(e.g., ``yum --disablerepo='somerepo'``)
.. code-block:: yaml
MyGroup:
pkg.group_installed:
- disablerepo: epel
.. versionadded:: 3006.2
.. note::
Because this is essentially a wrapper around :py:func:`pkg.install
<salt.modules.yumpkg.install>`, any argument which can be passed to
Expand Down Expand Up @@ -3371,7 +3413,7 @@ def group_installed(name, skip=None, include=None, **kwargs):
include[idx] = str(item)

try:
diff = __salt__["pkg.group_diff"](name)
diff = __salt__["pkg.group_diff"](name, **kwargs)
except CommandExecutionError as err:
ret[
"comment"
Expand Down
114 changes: 106 additions & 8 deletions tests/pytests/unit/states/test_pkg.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import textwrap

import pytest

Expand Down Expand Up @@ -87,7 +88,6 @@ def test_uptodate_with_changes(pkgs):
"pkg.version": version,
},
):

# Run state with test=false
with patch.dict(pkg.__opts__, {"test": False}):
ret = pkg.uptodate("dummy", test=True)
Expand Down Expand Up @@ -151,10 +151,8 @@ def test_uptodate_no_changes():
with patch.dict(
pkg.__salt__, {"pkg.list_upgrades": list_upgrades, "pkg.upgrade": upgrade}
):

# Run state with test=false
with patch.dict(pkg.__opts__, {"test": False}):

ret = pkg.uptodate("dummy", test=True)
assert ret["result"]
assert ret["changes"] == {}
Expand Down Expand Up @@ -564,7 +562,6 @@ def test_installed_with_changes_test_true(list_pkgs):
"pkg.list_pkgs": list_pkgs,
},
):

expected = {"dummy": {"new": "installed", "old": ""}}
# Run state with test=true
with patch.dict(pkg.__opts__, {"test": True}):
Expand Down Expand Up @@ -617,7 +614,6 @@ def test_removed_purged_with_changes_test_true(list_pkgs, action):
"pkg_resource.version_clean": MagicMock(return_value=None),
},
):

expected = {"pkga": {"new": "{}".format(action), "old": ""}}
pkg_actions = {"removed": pkg.removed, "purged": pkg.purged}

Expand Down Expand Up @@ -845,7 +841,6 @@ def test_installed_with_single_normalize():
), patch.object(
yumpkg, "list_holds", MagicMock()
):

expected = {
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
"old": "",
Expand Down Expand Up @@ -940,7 +935,6 @@ def test_removed_with_single_normalize():
), patch.dict(
yumpkg.__salt__, salt_dict
):

expected = {
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
"old": "20220214-2.1",
Expand Down Expand Up @@ -1034,7 +1028,6 @@ def test_installed_with_single_normalize_32bit():
), patch.dict(
yumpkg.__grains__, {"os": "CentOS", "osarch": "x86_64", "osmajorrelease": 7}
):

expected = {
"xz-devel.i686": {
"old": "",
Expand All @@ -1049,3 +1042,108 @@ def test_installed_with_single_normalize_32bit():
assert "xz-devel.i686" in call_yum_mock.mock_calls[0].args[0]
assert ret["result"]
assert ret["changes"] == expected


@pytest.mark.parametrize(
"kwargs, expected_cli_options",
(
(
(
"fromrepo=foo,bar",
"someotherkwarg=test",
"disablerepo=ignored",
"enablerepo=otherignored",
"disableexcludes=this_argument_is_also_ignored",
),
("--disablerepo=*", "--enablerepo=foo,bar"),
),
(
("enablerepo=foo", "disablerepo=bar"),
("--disablerepo=bar", "--enablerepo=foo"),
),
(
("disablerepo=foo",),
("--disablerepo=foo",),
),
(
("enablerepo=bar",),
("--enablerepo=bar",),
),
),
)
def test_group_installed_with_repo_options(list_pkgs, kwargs, expected_cli_options):
"""
Test that running a pkg.group_installed with repo options works results in
the correct yum/dnf groupinfo command being run by pkg.group_info.
"""
kwargs = dict(item.split("=", 1) for item in kwargs)
run_stdout = MagicMock(
return_value=textwrap.dedent(
"""\
Group: MyGroup
Group-Id: my-group
Description: A test group
Mandatory Packages:
pkga
pkgb
"""
)
)

salt_dict = {
"cmd.run_stdout": run_stdout,
"pkg.group_diff": yumpkg.group_diff,
"pkg.group_info": yumpkg.group_info,
}

# Need to mock yumpkg.list_pkgs() to return list_pkgs

name = "MyGroup"
with patch.dict(pkg.__salt__, salt_dict), patch.dict(
yumpkg.__salt__, salt_dict
), patch.object(
yumpkg,
"list_pkgs",
MagicMock(return_value=list_pkgs),
):
ret = pkg.group_installed(name, **kwargs)
assert ret["result"]
assert not ret["changes"]
expected = [yumpkg._yum(), "--quiet"]
expected.extend(expected_cli_options)
expected.extend(("groupinfo", name))
run_stdout.assert_called_once_with(
expected,
output_loglevel="trace",
python_shell=False,
)


def test__get_installable_versions_no_version_found():
mock_latest_versions = MagicMock(return_value={})
mock_list_repo_pkgs = MagicMock(return_value={})
with patch.dict(
pkg.__salt__,
{
"pkg.latest_version": mock_latest_versions,
"pkg.list_pkgs": mock_list_repo_pkgs,
},
), patch.dict(pkg.__opts__, {"test": True}):
expected = {"dummy": {"new": "installed", "old": ""}}
ret = pkg._get_installable_versions({"dummy": None}, current=None)
assert ret == expected


def test__get_installable_versions_version_found():
mock_latest_versions = MagicMock(return_value={"dummy": "1.0.1"})
mock_list_repo_pkgs = MagicMock(return_value={})
with patch.dict(
pkg.__salt__,
{
"pkg.latest_version": mock_latest_versions,
"pkg.list_pkgs": mock_list_repo_pkgs,
},
), patch.dict(pkg.__opts__, {"test": True}):
expected = {"dummy": {"new": "1.0.1", "old": ""}}
ret = pkg._get_installable_versions({"dummy": None}, current=None)
assert ret == expected

0 comments on commit 3e73ae4

Please sign in to comment.