diff --git a/changelog/60931.fixed.md b/changelog/60931.fixed.md new file mode 100644 index 000000000000..b0b980ccf858 --- /dev/null +++ b/changelog/60931.fixed.md @@ -0,0 +1 @@ +pkg.latest no longer fails when multiple versions are reported to be installed (e.g. updating the kernel) diff --git a/doc/ref/modules/index.rst b/doc/ref/modules/index.rst index 59f7c003aaa8..ca9171383c51 100644 --- a/doc/ref/modules/index.rst +++ b/doc/ref/modules/index.rst @@ -416,6 +416,8 @@ The above example will force the minion to use the :py:mod:`systemd ` module to provide service management, and the :py:mod:`aptpkg ` module to provide package management. +For per-state provider overrides, see documentation on :ref:`state providers `. + .. __: https://github.com/saltstack/salt/issues/new Logging Restrictions diff --git a/salt/beacons/smartos_imgadm.py b/salt/beacons/smartos_imgadm.py index d0460789f96d..2432a54e79fd 100644 --- a/salt/beacons/smartos_imgadm.py +++ b/salt/beacons/smartos_imgadm.py @@ -105,6 +105,3 @@ def beacon(config): IMGADM_STATE["first_run"] = False return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/beacons/smartos_vmadm.py b/salt/beacons/smartos_vmadm.py index 163aed8a38b8..fd48253785bc 100644 --- a/salt/beacons/smartos_vmadm.py +++ b/salt/beacons/smartos_vmadm.py @@ -132,6 +132,3 @@ def beacon(config): VMADM_STATE["first_run"] = False return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/grains/mdata.py b/salt/grains/mdata.py index 3077f321cc91..fe88f6ce2a68 100644 --- a/salt/grains/mdata.py +++ b/salt/grains/mdata.py @@ -152,6 +152,3 @@ def mdata(): ) return grains - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/grains/smartos.py b/salt/grains/smartos.py index 6195908ceca8..62e24b3798b0 100644 --- a/salt/grains/smartos.py +++ b/salt/grains/smartos.py @@ -213,6 +213,3 @@ def smartos(): ) return grains - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/grains/zfs.py b/salt/grains/zfs.py index e903d010832a..62f8f3def79a 100644 --- a/salt/grains/zfs.py +++ b/salt/grains/zfs.py @@ -81,6 +81,3 @@ def zfs(): ) return grains - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/apcups.py b/salt/modules/apcups.py index 084720f890b1..2b653061db5e 100644 --- a/salt/modules/apcups.py +++ b/salt/modules/apcups.py @@ -113,6 +113,3 @@ def status_battery(): return not data["TONBATT"] == "0 Seconds" return {"Error": "Battery status not available."} - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/at.py b/salt/modules/at.py index bf77cf0b7bdc..9c646dfb2e8c 100644 --- a/salt/modules/at.py +++ b/salt/modules/at.py @@ -245,6 +245,7 @@ def at(*args, **kwargs): # pylint: disable=C0103 salt '*' at.at [tag=] [runas=] salt '*' at.at 12:05am '/sbin/reboot' tag=reboot salt '*' at.at '3:05am +3 days' 'bin/myscript' tag=nightly runas=jim + salt '*' at.at '"22:02"' 'bin/myscript' tag=nightly runas=jim """ if len(args) < 2: diff --git a/salt/modules/at_solaris.py b/salt/modules/at_solaris.py index 462cf9b8c94a..ee8e2e67b358 100644 --- a/salt/modules/at_solaris.py +++ b/salt/modules/at_solaris.py @@ -342,6 +342,3 @@ def jobcheck(**kwargs): return {"error": "You have given a condition"} return _atq(**kwargs) - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/bridge.py b/salt/modules/bridge.py index 1bac60f2b09e..edc9c9dc3773 100644 --- a/salt/modules/bridge.py +++ b/salt/modules/bridge.py @@ -489,6 +489,3 @@ def stp(br=None, state="disable", iface=None): return _os_dispatch("stp", br, states[state], iface) else: return False - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/mdata.py b/salt/modules/mdata.py index 13f2e4cb3968..9b31be55dbc4 100644 --- a/salt/modules/mdata.py +++ b/salt/modules/mdata.py @@ -176,6 +176,3 @@ def delete_(*keyname): ret[k] = True return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/netbsd_sysctl.py b/salt/modules/netbsd_sysctl.py index 648120b59b60..cd18ea36e475 100644 --- a/salt/modules/netbsd_sysctl.py +++ b/salt/modules/netbsd_sysctl.py @@ -159,6 +159,3 @@ def persist(name, value, config="/etc/sysctl.conf"): assign(name, value) return "Updated" - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/netbsdservice.py b/salt/modules/netbsdservice.py index 7b36be1a214d..e8308415930e 100644 --- a/salt/modules/netbsdservice.py +++ b/salt/modules/netbsdservice.py @@ -310,6 +310,3 @@ def disabled(name): salt '*' service.disabled """ return _get_svc("/etc/rc.d/{}".format(name), "NO") - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/pdbedit.py b/salt/modules/pdbedit.py index e35283eb08e5..45af6fb1ca8f 100644 --- a/salt/modules/pdbedit.py +++ b/salt/modules/pdbedit.py @@ -406,6 +406,3 @@ def modify( ret = "updated" return {login: ret} - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/pkgin.py b/salt/modules/pkgin.py index c27b6ed8fceb..8380360047ca 100644 --- a/salt/modules/pkgin.py +++ b/salt/modules/pkgin.py @@ -701,6 +701,3 @@ def normalize_name(pkgs, **kwargs): with the pkg_resource provider.) """ return pkgs - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/rbac_solaris.py b/salt/modules/rbac_solaris.py index a740bf946217..876eaf0bf70f 100644 --- a/salt/modules/rbac_solaris.py +++ b/salt/modules/rbac_solaris.py @@ -634,6 +634,3 @@ def auth_rm(user, auth): ret[a] = "Remove" return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/runit.py b/salt/modules/runit.py index 2a5e655c2bbf..29f95bf377bb 100644 --- a/salt/modules/runit.py +++ b/salt/modules/runit.py @@ -726,6 +726,3 @@ def remove(name): log.error("Unable to remove symlink %s", svc_path) return False return True - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/slackware_service.py b/salt/modules/slackware_service.py index 51562d030326..54bc3c2a77fb 100644 --- a/salt/modules/slackware_service.py +++ b/salt/modules/slackware_service.py @@ -349,6 +349,3 @@ def disabled(name): if _get_svc("{}.{}".format(prefix, name), "OFF") is None: ret = False return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/smartos_imgadm.py b/salt/modules/smartos_imgadm.py index 688371cdd249..5d5cb75e7508 100644 --- a/salt/modules/smartos_imgadm.py +++ b/salt/modules/smartos_imgadm.py @@ -508,6 +508,3 @@ def source_add(source, source_type="imgapi"): return ret return sources(False) - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/smartos_nictagadm.py b/salt/modules/smartos_nictagadm.py index e2991be6708d..99d09826e287 100644 --- a/salt/modules/smartos_nictagadm.py +++ b/salt/modules/smartos_nictagadm.py @@ -263,6 +263,3 @@ def delete(name, force=False): if "stderr" not in res and res["stderr"] == "" else res["stderr"] } - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/smartos_vmadm.py b/salt/modules/smartos_vmadm.py index 4e5b97baddf9..3ef9c3d5b6a2 100644 --- a/salt/modules/smartos_vmadm.py +++ b/salt/modules/smartos_vmadm.py @@ -875,6 +875,3 @@ def receive(uuid, source): ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/solaris_fmadm.py b/salt/modules/solaris_fmadm.py index 7617bed56db1..7dae9d6b100f 100644 --- a/salt/modules/solaris_fmadm.py +++ b/salt/modules/solaris_fmadm.py @@ -509,6 +509,3 @@ def healthy(): salt '*' fmadm.healthy """ return False if faulty() else True - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/zcbuildout.py b/salt/modules/zcbuildout.py index 6d06bfa5ac77..99b9202011e9 100644 --- a/salt/modules/zcbuildout.py +++ b/salt/modules/zcbuildout.py @@ -1023,6 +1023,3 @@ def _check_onlyif_unless(onlyif, unless, directory, runas=None, env=()): if status["status"]: ret = status return ret - - -# vim:set et sts=4 ts=4 tw=80: diff --git a/salt/modules/zfs.py b/salt/modules/zfs.py index d583108a43a9..7df620e3eb65 100644 --- a/salt/modules/zfs.py +++ b/salt/modules/zfs.py @@ -1249,6 +1249,3 @@ def get(*dataset, **kwargs): del ds_data["property"] return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/zoneadm.py b/salt/modules/zoneadm.py index 4b2b91c0d22a..0bb4a60e26ed 100644 --- a/salt/modules/zoneadm.py +++ b/salt/modules/zoneadm.py @@ -570,6 +570,3 @@ def clone(zone, source, snapshot=None): del ret["message"] return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/modules/zonecfg.py b/salt/modules/zonecfg.py index bf3b913faf64..a90408047970 100644 --- a/salt/modules/zonecfg.py +++ b/salt/modules/zonecfg.py @@ -799,6 +799,3 @@ def info(zone, show_all=False): ret[resname].append(resdata) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/runners/smartos_vmadm.py b/salt/runners/smartos_vmadm.py index 052c70b60175..7575fdbaf184 100644 --- a/salt/runners/smartos_vmadm.py +++ b/salt/runners/smartos_vmadm.py @@ -383,6 +383,3 @@ def is_running(search): salt-run vmadm.is_running search='alias=julia' """ return _action("is_running", search, False) - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/at.py b/salt/states/at.py index 2e1dec6ad4d2..a4065314552a 100644 --- a/salt/states/at.py +++ b/salt/states/at.py @@ -296,6 +296,3 @@ def mod_watch(name, **kwargs): ret = present(**kwargs) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/logadm.py b/salt/states/logadm.py index 53382dd6fec3..d2b33e32b4f7 100644 --- a/salt/states/logadm.py +++ b/salt/states/logadm.py @@ -161,6 +161,3 @@ def remove(name, log_file=None): ret["comment"] = "No configuration for {} present.".format(log_file) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/pdbedit.py b/salt/states/pdbedit.py index 15d7cdd17530..8a2848f4d392 100644 --- a/salt/states/pdbedit.py +++ b/salt/states/pdbedit.py @@ -141,6 +141,3 @@ def present(name, **kwargs): Alias for pdbedit.managed """ return managed(name, **kwargs) - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 65a0fef10558..aea68f94f52d 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -2789,7 +2789,7 @@ def latest( x for x in targets if not changes.get(x) - or changes[x].get("new") != targets[x] + or targets[x] not in changes[x].get("new").split(",") and targets[x] != "latest" ] successful = [x for x in targets if x not in failed] diff --git a/salt/states/smartos.py b/salt/states/smartos.py index 9ae2c722036e..7420d6ba33ff 100644 --- a/salt/states/smartos.py +++ b/salt/states/smartos.py @@ -1311,6 +1311,3 @@ def vm_stopped(name): ret["comment"] = "vm {} stopped".format(name) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/zfs.py b/salt/states/zfs.py index 855ec6383410..b28517ed5a12 100644 --- a/salt/states/zfs.py +++ b/salt/states/zfs.py @@ -1090,6 +1090,3 @@ def scheduled_snapshot(name, prefix, recursive=True, schedule=None): ret["comment"] = "scheduled snapshots are up to date" return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/zone.py b/salt/states/zone.py index 3d8d07bb6f87..d411ad33a0aa 100644 --- a/salt/states/zone.py +++ b/salt/states/zone.py @@ -1274,6 +1274,3 @@ def uninstalled(name): ret["comment"] = "zone {} is not configured!".format(name) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/states/zpool.py b/salt/states/zpool.py index 9900dde9ea1f..4c8c7b4f3af3 100644 --- a/salt/states/zpool.py +++ b/salt/states/zpool.py @@ -442,6 +442,3 @@ def absent(name, export=False, force=False): ret["comment"] = "storage pool {} is absent".format(name) return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/salt/utils/job.py b/salt/utils/job.py index a734b015a7c5..14b16b85a6ed 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -198,6 +198,3 @@ def get_keep_jobs_seconds(opts): ) keep_jobs_seconds = keep_jobs * 3600 return keep_jobs_seconds - - -# vim:set et sts=4 ts=4 tw=80: diff --git a/salt/utils/zfs.py b/salt/utils/zfs.py index 98546298e7b0..3c38cecc7aa6 100644 --- a/salt/utils/zfs.py +++ b/salt/utils/zfs.py @@ -755,6 +755,3 @@ def parse_command_result(res, label=None): del ret["error"] return ret - - -# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/integration/files/file/base/_states/salttest.py b/tests/integration/files/file/base/_states/salttest.py index 596e71213150..e7288a9a95d9 100644 --- a/tests/integration/files/file/base/_states/salttest.py +++ b/tests/integration/files/file/base/_states/salttest.py @@ -6,6 +6,3 @@ def hello(name): return "hello " + name - - -# vim:set et sts=4 ts=4 tw=80: diff --git a/tests/pytests/unit/beacons/test_inotify.py b/tests/pytests/unit/beacons/test_inotify.py index 30a9a91db4b5..16b5f9e840bc 100644 --- a/tests/pytests/unit/beacons/test_inotify.py +++ b/tests/pytests/unit/beacons/test_inotify.py @@ -26,6 +26,14 @@ def configure_loader_modules(): return {inotify: {}} +@pytest.fixture(autouse=True) +def _close_inotify(configure_loader_modules): + try: + yield + finally: + inotify.close({}) + + def test_non_list_config(): config = {} diff --git a/tests/pytests/unit/beacons/test_watchdog.py b/tests/pytests/unit/beacons/test_watchdog.py index df150a028ef5..de622b5ea0d8 100644 --- a/tests/pytests/unit/beacons/test_watchdog.py +++ b/tests/pytests/unit/beacons/test_watchdog.py @@ -45,6 +45,14 @@ def configure_loader_modules(): return {watchdog: {}} +@pytest.fixture(autouse=True) +def _close_watchdog(configure_loader_modules): + try: + yield + finally: + watchdog.close({}) + + def assertValid(config): ret = watchdog.validate(config) assert ret == (True, "Valid beacon configuration") diff --git a/tests/pytests/unit/states/test_pkg.py b/tests/pytests/unit/states/test_pkg.py index 19b11c8af0cb..2071f33ea793 100644 --- a/tests/pytests/unit/states/test_pkg.py +++ b/tests/pytests/unit/states/test_pkg.py @@ -1140,3 +1140,59 @@ def test_pacmanpkg_group_installed_with_repo_options(list_pkgs): assert not ret["result"] assert not ret["changes"] assert ret["comment"] == "Repo options are not supported on this platform" + + +def test_latest(): + """ + Test pkg.latest + """ + pkg_name = "fake_pkg" + old_version = "1.2.2" + new_version = "1.2.3" + latest_version_mock = MagicMock(return_value={pkg_name: new_version}) + current_version_mock = MagicMock(return_value={pkg_name: old_version}) + install_mock = MagicMock( + return_value={ + pkg_name: { + "new": new_version, + "old": old_version, + }, + } + ) + salt_dict = { + "pkg.latest_version": latest_version_mock, + "pkg.version": current_version_mock, + "pkg.install": install_mock, + } + with patch.dict(pkg.__salt__, salt_dict): + ret = pkg.latest(pkg_name) + assert ret.get("result", False) is True + + +def test_latest_multiple_versions(): + """ + This case arises most often when updating the kernel, where multiple versions are now installed. + + See: https://github.com/saltstack/salt/issues/60931 + """ + pkg_name = "fake_pkg" + old_version = "1.2.2" + new_version = "1.2.3" + latest_version_mock = MagicMock(return_value={pkg_name: new_version}) + current_version_mock = MagicMock(return_value={pkg_name: old_version}) + install_mock = MagicMock( + return_value={ + pkg_name: { + "new": f"{old_version},{new_version}", + "old": old_version, + }, + } + ) + salt_dict = { + "pkg.latest_version": latest_version_mock, + "pkg.version": current_version_mock, + "pkg.install": install_mock, + } + with patch.dict(pkg.__salt__, salt_dict): + ret = pkg.latest(pkg_name) + assert ret.get("result", False) is True diff --git a/tests/support/ext/console.py b/tests/support/ext/console.py index 41e2dd466a04..8c54638fd5e4 100644 --- a/tests/support/ext/console.py +++ b/tests/support/ext/console.py @@ -1,4 +1,3 @@ -# vim: sw=4 ts=4 fenc=utf-8 """ getTerminalSize() - get width and height of console diff --git a/tools/utils.py b/tools/utils.py index 48dc4a173142..76c107642295 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -34,7 +34,7 @@ REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent GPG_KEY_FILENAME = "SALT-PROJECT-GPG-PUBKEY-2023" -SPB_ENVIRONMENT = os.environ.get("SPB_ENVIRONMENT") or "prod" +SPB_ENVIRONMENT = os.environ.get("SPB_ENVIRONMENT") or "test" STAGING_BUCKET_NAME = f"salt-project-{SPB_ENVIRONMENT}-salt-artifacts-staging" RELEASE_BUCKET_NAME = f"salt-project-{SPB_ENVIRONMENT}-salt-artifacts-release" BACKUP_BUCKET_NAME = f"salt-project-{SPB_ENVIRONMENT}-salt-artifacts-backup"