Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package salt for openSUSE:Factory checked in at 2026-06-25 10:49:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/salt (Old) and /work/SRC/openSUSE:Factory/.salt.new.2088 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "salt" Thu Jun 25 10:49:59 2026 rev:199 rq:1361354 version:3006.0 Changes: -------- --- /work/SRC/openSUSE:Factory/salt/salt.changes 2026-06-18 18:39:32.774332888 +0200 +++ /work/SRC/openSUSE:Factory/.salt.new.2088/salt.changes 2026-06-25 10:51:47.738137177 +0200 @@ -1,0 +2,16 @@ +Tue Jun 23 10:03:47 UTC 2026 - Victor Zhestkov <[email protected]> + +- Fix the tests failing after switching to non-vendored tornado +- Fix the default group in tests for new users in SLE 15.6 +- Use AsyncHTTPClient in salt.utils.http (bsc#1268325) +- Fix file fetching with cp module on non-vendored tornado +- Decode binary pillars for salt-ssh to avoid exceptions (bsc#1263822) + +- Added: + * fix-the-tests-failing-after-switching-to-non-vendore.patch + * fix-the-default-group-in-tests-for-new-users-in-sle-.patch + * use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch + * fix-file-fetching-with-non-vendored-tornado.patch + * decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch + +------------------------------------------------------------------- New: ---- decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch fix-file-fetching-with-non-vendored-tornado.patch fix-the-default-group-in-tests-for-new-users-in-sle-.patch fix-the-tests-failing-after-switching-to-non-vendore.patch use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch ----------(New B)---------- New: * fix-file-fetching-with-non-vendored-tornado.patch * decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch New: * use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch * fix-file-fetching-with-non-vendored-tornado.patch * decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch New: * fix-the-tests-failing-after-switching-to-non-vendore.patch * fix-the-default-group-in-tests-for-new-users-in-sle-.patch * use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch New:- Added: * fix-the-tests-failing-after-switching-to-non-vendore.patch * fix-the-default-group-in-tests-for-new-users-in-sle-.patch New: * fix-the-default-group-in-tests-for-new-users-in-sle-.patch * use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch * fix-file-fetching-with-non-vendored-tornado.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ salt.spec ++++++ --- /var/tmp/diff_new_pack.ZMqCCc/_old 2026-06-25 10:51:52.422299397 +0200 +++ /var/tmp/diff_new_pack.ZMqCCc/_new 2026-06-25 10:51:52.426299535 +0200 @@ -654,6 +654,21 @@ # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/69363 # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/765 Patch209: fix-importerror-during-reentrant-sigterm-shutdown.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/69405 +Patch210: decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/766 +# There is no upstream PR behind as upstream relies on non-vendored tornado +# with higher version which doesn't have this issue +Patch211: fix-file-fetching-with-non-vendored-tornado.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/0b92bfdf80ab40787072d546b6962c77dd24e0b7 +Patch212: use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/758 +Patch213: fix-the-default-group-in-tests-for-new-users-in-sle-.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/e37d3e405a0c7d417a45804272933afa7ccae40b +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/dfe321bc1564fbaa7b6a19ff0f78a05cae45d3d0 +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/commit/e8c016419b73aaefab32880fe91ad694f0c6668e +Patch214: fix-the-tests-failing-after-switching-to-non-vendore.patch + ### IMPORTANT: The line below is used as a snippet marker. Do not touch it. ### SALT PATCHES LIST END ++++++ _lastrevision ++++++ --- /var/tmp/diff_new_pack.ZMqCCc/_old 2026-06-25 10:51:52.586305076 +0200 +++ /var/tmp/diff_new_pack.ZMqCCc/_new 2026-06-25 10:51:52.590305215 +0200 @@ -1,3 +1,3 @@ -8b29071b585079ded431c8d93864e3b7470acff7 +2439b01e36ab77ded85262a47edabc2c472bf330 (No newline at EOF) ++++++ decode-binary-pillars-for-salt-ssh-to-avoid-exceptio.patch ++++++ >From d1a3fc8e8d65aaac500ea40ef40e2090a58ba5f6 Mon Sep 17 00:00:00 2001 From: Victor Zhestkov <[email protected]> Date: Tue, 23 Jun 2026 09:46:30 +0200 Subject: [PATCH] Decode binary pillars for salt-ssh to avoid exceptions (bsc#1263822) * Avoid exception on pillar data serialization with salt-ssh * Add test for prep_trans_tar binary pillar data decode --- salt/client/ssh/state.py | 2 + tests/pytests/unit/client/ssh/test_state.py | 56 +++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/pytests/unit/client/ssh/test_state.py diff --git a/salt/client/ssh/state.py b/salt/client/ssh/state.py index 4ee62a293a..ec5c65d7b8 100644 --- a/salt/client/ssh/state.py +++ b/salt/client/ssh/state.py @@ -15,6 +15,7 @@ import salt.loader import salt.minion import salt.roster import salt.state +import salt.utils.data import salt.utils.files import salt.utils.json import salt.utils.path @@ -203,6 +204,7 @@ def prep_trans_tar( salt.utils.json.dump(chunks, fp_) if pillar: with salt.utils.files.fopen(pillarfn, "w+") as fp_: + pillar = salt.utils.data.decode_dict(pillar) salt.utils.json.dump(pillar, fp_) if roster_grains: with salt.utils.files.fopen(roster_grainsfn, "w+") as fp_: diff --git a/tests/pytests/unit/client/ssh/test_state.py b/tests/pytests/unit/client/ssh/test_state.py new file mode 100644 index 0000000000..3f1424f3dd --- /dev/null +++ b/tests/pytests/unit/client/ssh/test_state.py @@ -0,0 +1,56 @@ +import pytest + +from salt.client.ssh.state import prep_trans_tar +from tests.support.mock import patch + + [email protected]( + "inpt,expected", + [ + ( + { + "pillar_data_n1": 1, + "pillar_data_t2": "text2", + "pillar_data_d3": { + "text1": "text1", + "text2": "text2", + }, + }, + { + "pillar_data_n1": 1, + "pillar_data_t2": "text2", + "pillar_data_d3": { + "text1": "text1", + "text2": "text2", + }, + }, + ), + ( + { + "pillar_data_n1": 1, + "pillar_data_t2": "text2", + "pillar_data_b3": b"text3", + "pillar_data_d4": { + "bin1": b"bin1", + "bin2": b"bin2", + }, + }, + { + "pillar_data_n1": 1, + "pillar_data_t2": "text2", + "pillar_data_b3": "text3", + "pillar_data_d4": { + "bin1": "bin1", + "bin2": "bin2", + }, + }, + ), + ], +) +def test_prep_trans_tar_with_binary_pillar(inpt, expected): + """ + Test binary pillar serialization + """ + with patch("salt.utils.json.dump", return_value="") as json_dump_mock: + trans_tar = prep_trans_tar(None, [], [], pillar=inpt) + assert expected == json_dump_mock.call_args[0][0] -- 2.54.0 ++++++ fix-file-fetching-with-non-vendored-tornado.patch ++++++ >From 4b09fa3697dbf3ec27ef8b3e26ee95a498f07f99 Mon Sep 17 00:00:00 2001 From: Victor Zhestkov <[email protected]> Date: Tue, 23 Jun 2026 09:47:32 +0200 Subject: [PATCH] Fix file fetching with non-vendored tornado --- salt/fileclient.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/salt/fileclient.py b/salt/fileclient.py index 82e0fc2a82..744e850ade 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -12,7 +12,6 @@ import string import urllib.error import urllib.parse -from salt import USE_VENDORED_TORNADO from tornado.httputil import HTTPHeaders, HTTPInputError, parse_response_start_line import salt.channel.client @@ -745,8 +744,10 @@ class Client: # Check the status line of the HTTP request if write_body[0] is None: try: - hdr = hdr if USE_VENDORED_TORNADO else hdr.strip() - hdr = parse_response_start_line(hdr) + try: + hdr = parse_response_start_line(hdr) + except HTTPInputError: + hdr = parse_response_start_line(hdr.strip()) except HTTPInputError: # Not the first line, do nothing return -- 2.54.0 ++++++ fix-the-default-group-in-tests-for-new-users-in-sle-.patch ++++++ >From 6e555748cfc62add44a523b0aebc31d2f33f26e4 Mon Sep 17 00:00:00 2001 From: Marek Czernek <[email protected]> Date: Tue, 23 Jun 2026 09:49:52 +0200 Subject: [PATCH] Fix the default group in tests for new users in SLE 15.6 In SLE 15.6 and newer, the default group changed from users(100) to $username(1000) --- tests/pytests/functional/states/test_user.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/pytests/functional/states/test_user.py b/tests/pytests/functional/states/test_user.py index 231841ee78..4060e049d0 100644 --- a/tests/pytests/functional/states/test_user.py +++ b/tests/pytests/functional/states/test_user.py @@ -139,7 +139,9 @@ def test_user_present_nondefault(grains, modules, states, username, user_home): assert user_home.is_dir() if grains["os_family"] == "Suse" and not ( - grains.get("transactional", False) or grains.get("osmajorrelease", 0) >= 16 + grains.get("transactional", False) + or grains.get("osmajorrelease", 0) >= 16 + or grains.get("osrelease_info", ()) >= (15, 6) ): expected_group_name = "users" elif grains["os_family"] == "MacOS": @@ -388,7 +390,9 @@ def test_user_present_change_groups( ): expected_groups = [group_2.name, group_1.name] if grains["os_family"] == "Suse" and ( - grains.get("transactional", False) or grains.get("osmajorrelease", 0) >= 16 + grains.get("transactional", False) + or grains.get("osmajorrelease", 0) >= 16 + or grains.get("osrelease_info", ()) >= (15, 6) ): expected_groups.append(username) @@ -422,7 +426,9 @@ def test_user_present_change_optional_groups( ): expected_groups = [group_2.name, group_1.name] if grains["os_family"] == "Suse" and ( - grains.get("transactional", False) or grains.get("osmajorrelease", 0) >= 16 + grains.get("transactional", False) + or grains.get("osmajorrelease", 0) >= 16 + or grains.get("osrelease_info", ()) >= (15, 6) ): expected_groups.append(username) -- 2.54.0 ++++++ fix-the-tests-failing-after-switching-to-non-vendore.patch ++++++ >From e12daef9952ec917b4aaf8ea9a1fcb65e3ff6aff Mon Sep 17 00:00:00 2001 From: Victor Zhestkov <[email protected]> Date: Tue, 23 Jun 2026 10:21:10 +0200 Subject: [PATCH] Fix the tests failing after switching to non-vendored tornado --- salt/utils/asynchronous.py | 25 ++++++++++++++++--- .../pytests/functional/channel/test_server.py | 6 +++++ .../netapi/rest_cherrypy/conftest.py | 2 +- .../test_external_auth_syntax.py | 2 +- .../netapi/rest_cherrypy/conftest.py | 2 +- tests/pytests/unit/transport/test_tcp.py | 9 +++---- tests/support/netapi.py | 2 +- 7 files changed, 36 insertions(+), 12 deletions(-) diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py index 0429bf9fcc..403b2dbdc3 100644 --- a/salt/utils/asynchronous.py +++ b/salt/utils/asynchronous.py @@ -16,19 +16,38 @@ from salt import USE_VENDORED_TORNADO log = logging.getLogger(__name__) +def aioloop(io_loop, warn=False): + """ + Ensure the ioloop is an asyncio loop not a tornado ioloop. + """ + if isinstance(io_loop, asyncio.AbstractEventLoop): + return io_loop + elif isinstance(io_loop, tornado.ioloop.IOLoop): + if warn: + import traceback + + log.warning("Passed tornado loop %s", "".join(traceback.format_stack())) + return io_loop.asyncio_loop + else: + raise RuntimeError("Loop must be AbstractEventLoop (prefered) or IOLoop") + + @contextlib.contextmanager def current_ioloop(io_loop): """ A context manager that will set the current ioloop to io_loop for the context """ try: - orig_loop = tornado.ioloop.IOLoop.current() + # Use instance=False to avoid auto-creating a default IOLoop that leaks FDs + orig_loop = tornado.ioloop.IOLoop.current(instance=False) except RuntimeError: orig_loop = None if USE_VENDORED_TORNADO: io_loop.make_current() else: - asyncio.set_event_loop(io_loop.asyncio_loop) + # Normalize io_loop to asyncio loop + asyncio_loop = aioloop(io_loop) + asyncio.set_event_loop(asyncio_loop) try: yield finally: @@ -36,7 +55,7 @@ def current_ioloop(io_loop): if USE_VENDORED_TORNADO: orig_loop.make_current() else: - asyncio.set_event_loop(orig_loop.asyncio_loop) + asyncio.set_event_loop(aioloop(orig_loop)) else: asyncio.set_event_loop(None) diff --git a/tests/pytests/functional/channel/test_server.py b/tests/pytests/functional/channel/test_server.py index 37a75c16dd..be8c27d3fd 100644 --- a/tests/pytests/functional/channel/test_server.py +++ b/tests/pytests/functional/channel/test_server.py @@ -21,6 +21,8 @@ import salt.utils.platform import salt.utils.process import salt.utils.stringutils +from salt import USE_VENDORED_TORNADO + log = logging.getLogger(__name__) @@ -138,6 +140,10 @@ def _connect_and_publish( io_loop.stop() [email protected]( + not USE_VENDORED_TORNADO, + reason="Could stuck with some versions of non-vendored tornado", +) def test_pub_server_channel( io_loop, channel_minion_id, diff --git a/tests/pytests/functional/netapi/rest_cherrypy/conftest.py b/tests/pytests/functional/netapi/rest_cherrypy/conftest.py index 90b43f938e..93b9a61cf0 100644 --- a/tests/pytests/functional/netapi/rest_cherrypy/conftest.py +++ b/tests/pytests/functional/netapi/rest_cherrypy/conftest.py @@ -29,7 +29,7 @@ def app(client_config, load_auth): @pytest.fixture -def http_server(io_loop, app, netapi_port): +def http_server(app, netapi_port, io_loop): with netapi.TestsTornadoHttpServer( io_loop=io_loop, app=app, port=netapi_port ) as server: diff --git a/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py b/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py index 6a85f33900..5f36e3274b 100644 --- a/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py +++ b/tests/pytests/functional/netapi/rest_cherrypy/test_external_auth_syntax.py @@ -278,7 +278,7 @@ def client_config(client_config, external_auth): @pytest.fixture -def http_server(io_loop, app, netapi_port, content_type_map): +def http_server(app, netapi_port, content_type_map, io_loop): with netapi.TestsTornadoHttpServer( io_loop=io_loop, app=app, diff --git a/tests/pytests/integration/netapi/rest_cherrypy/conftest.py b/tests/pytests/integration/netapi/rest_cherrypy/conftest.py index 213b0390ae..f3316aeb6d 100644 --- a/tests/pytests/integration/netapi/rest_cherrypy/conftest.py +++ b/tests/pytests/integration/netapi/rest_cherrypy/conftest.py @@ -35,7 +35,7 @@ def client_headers(auth_token, content_type_map): @pytest.fixture -def http_server(io_loop, app, netapi_port, client_headers): +def http_server(app, netapi_port, client_headers, io_loop): with netapi.TestsTornadoHttpServer( io_loop=io_loop, app=app, port=netapi_port, client_headers=client_headers ) as server: diff --git a/tests/pytests/unit/transport/test_tcp.py b/tests/pytests/unit/transport/test_tcp.py index 537395d04c..d6bdbf654e 100644 --- a/tests/pytests/unit/transport/test_tcp.py +++ b/tests/pytests/unit/transport/test_tcp.py @@ -240,12 +240,9 @@ def test_tcp_pub_server_channel_publish_filtering_str_list(temp_salt_master): @pytest.fixture(scope="function") -def salt_message_client(): - io_loop_mock = MagicMock(spec=tornado.ioloop.IOLoop) - io_loop_mock.call_later.side_effect = lambda *args, **kwargs: (args, kwargs) - +def salt_message_client(io_loop): client = salt.transport.tcp.MessageClient( - {}, "127.0.0.1", ports.get_unused_localhost_port(), io_loop=io_loop_mock + {}, "127.0.0.1", ports.get_unused_localhost_port(), io_loop=io_loop ) try: @@ -457,6 +454,8 @@ def test_presence_removed_on_stream_closed(): opts = {"presence_events": True} io_loop_mock = MagicMock(spec=tornado.ioloop.IOLoop) + # Add asyncio_loop attribute for aioloop() compatibility + io_loop_mock.asyncio_loop = MagicMock() with patch("salt.master.AESFuncs.__init__", return_value=None): server = salt.transport.tcp.PubServer(opts, io_loop=io_loop_mock) diff --git a/tests/support/netapi.py b/tests/support/netapi.py index 5095a5998d..3926a69327 100644 --- a/tests/support/netapi.py +++ b/tests/support/netapi.py @@ -79,7 +79,7 @@ class TestsTornadoHttpServer: @server.default def _server_default(self): - server = HTTPServer(self.app, io_loop=self.io_loop, **self.http_server_options) + server = HTTPServer(self.app, **self.http_server_options) server.add_sockets([self.sock]) return server -- 2.54.0 ++++++ use-asynchttpclient-in-salt.utils.http-bsc-1268325.patch ++++++ >From ce09c1048d3fe71e67f54000ff290c382a3d9d45 Mon Sep 17 00:00:00 2001 From: Marek Czernek <[email protected]> Date: Tue, 23 Jun 2026 09:48:54 +0200 Subject: [PATCH] Use AsyncHTTPClient in salt.utils.http (bsc#1268325) Backport of https://github.com/saltstack/salt/commit/0b92bfdf80ab40787072d546b6962c77dd24e0b7 --- salt/utils/http.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/salt/utils/http.py b/salt/utils/http.py index 9d0669a85b..bc9e095d32 100644 --- a/salt/utils/http.py +++ b/salt/utils/http.py @@ -38,9 +38,10 @@ import salt.utils.stringutils import salt.utils.xmlutil as xml import salt.utils.yaml import salt.version -from tornado.httpclient import HTTPClient +from tornado.httpclient import AsyncHTTPClient from salt.template import compile_template from salt.utils.decorators.jinja import jinja_filter +from salt.utils.asynchronous import SyncWrapper try: from ssl import CertificateError, match_hostname @@ -564,14 +565,14 @@ def query( log.error(ret["error"]) return ret - tornado.httpclient.AsyncHTTPClient.configure( + AsyncHTTPClient.configure( "tornado.curl_httpclient.CurlAsyncHTTPClient" ) client_argspec = salt.utils.args.get_function_argspec( tornado.curl_httpclient.CurlAsyncHTTPClient.initialize ) else: - tornado.httpclient.AsyncHTTPClient.configure(None) + AsyncHTTPClient.configure(None) client_argspec = salt.utils.args.get_function_argspec( tornado.simple_httpclient.SimpleAsyncHTTPClient.initialize ) @@ -606,10 +607,10 @@ def query( req_kwargs = salt.utils.data.decode(req_kwargs, to_str=True) try: - download_client = ( - HTTPClient(max_body_size=max_body) - if supports_max_body_size - else HTTPClient() + download_client = SyncWrapper( + AsyncHTTPClient, + kwargs={"max_body_size": max_body} if supports_max_body_size else {}, + async_methods=["fetch"], ) result = download_client.fetch(url_full, **req_kwargs) except tornado.httpclient.HTTPError as exc: -- 2.54.0
