From a5cf116d2bcc67cba4de0a052eb8ef71d039db2e8eba01184222820fa7167433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yeray=20Guti=C3=A9rrez=20Cedr=C3=A9s?= Date: Fri, 1 Dec 2023 12:24:54 +0000 Subject: [PATCH] Accepting request 1130201 from home:PSuarezHernandez:branches:systemsmanagement:saltstack - Enable "KeepAlive" probes for Salt SSH executions (bsc#1211649) - Added: * enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch OBS-URL: https://build.opensuse.org/request/show/1130201 OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=224 --- _lastrevision | 2 +- ...-probes-for-salt-ssh-executions-bsc-.patch | 346 ++++++++++++++++++ salt.changes | 8 + salt.spec | 2 + 4 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch diff --git a/_lastrevision b/_lastrevision index e56ccd2..69861cc 100644 --- a/_lastrevision +++ b/_lastrevision @@ -1 +1 @@ -56bc957ab216f66af02e5299b9e71fd4e82dd999 \ No newline at end of file +ecaf86de2f64a2032b60880651dde534021c8954 \ No newline at end of file diff --git a/enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch b/enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch new file mode 100644 index 0000000..8303a37 --- /dev/null +++ b/enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch @@ -0,0 +1,346 @@ +From 5303cc612bcbdb1ec45ede397ca1e2ca12ba3bd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Fri, 1 Dec 2023 10:59:30 +0000 +Subject: [PATCH] Enable "KeepAlive" probes for Salt SSH executions + (bsc#1211649) (#610) + +* Enable KeepAlive probes for Salt SSH connections (bsc#1211649) + +* Add tests for Salt SSH keepalive options + +* Add changelog file + +* Make changes suggested by pre-commit +--- + changelog/65488.added.md | 1 + + salt/client/ssh/__init__.py | 32 +++++++++--- + salt/client/ssh/client.py | 13 ++++- + salt/client/ssh/shell.py | 12 +++++ + salt/config/__init__.py | 6 +++ + salt/utils/parsers.py | 19 +++++++ + tests/pytests/unit/client/ssh/test_single.py | 55 ++++++++++++++++++++ + tests/pytests/unit/client/ssh/test_ssh.py | 3 ++ + 8 files changed, 133 insertions(+), 8 deletions(-) + create mode 100644 changelog/65488.added.md + +diff --git a/changelog/65488.added.md b/changelog/65488.added.md +new file mode 100644 +index 0000000000..78476cec11 +--- /dev/null ++++ b/changelog/65488.added.md +@@ -0,0 +1 @@ ++Enable "KeepAlive" probes for Salt SSH executions +diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py +index 1e143f9e30..1d8426b7c2 100644 +--- a/salt/client/ssh/__init__.py ++++ b/salt/client/ssh/__init__.py +@@ -50,8 +50,8 @@ import salt.utils.thin + import salt.utils.url + import salt.utils.verify + from salt._logging import LOG_LEVELS +-from salt._logging.mixins import MultiprocessingStateMixin + from salt._logging.impl import LOG_LOCK ++from salt._logging.mixins import MultiprocessingStateMixin + from salt.template import compile_template + from salt.utils.process import Process + from salt.utils.zeromq import zmq +@@ -307,6 +307,18 @@ class SSH(MultiprocessingStateMixin): + "ssh_timeout", salt.config.DEFAULT_MASTER_OPTS["ssh_timeout"] + ) + + self.opts.get("timeout", salt.config.DEFAULT_MASTER_OPTS["timeout"]), ++ "keepalive": self.opts.get( ++ "ssh_keepalive", ++ salt.config.DEFAULT_MASTER_OPTS["ssh_keepalive"], ++ ), ++ "keepalive_interval": self.opts.get( ++ "ssh_keepalive_interval", ++ salt.config.DEFAULT_MASTER_OPTS["ssh_keepalive_interval"], ++ ), ++ "keepalive_count_max": self.opts.get( ++ "ssh_keepalive_count_max", ++ salt.config.DEFAULT_MASTER_OPTS["ssh_keepalive_count_max"], ++ ), + "sudo": self.opts.get( + "ssh_sudo", salt.config.DEFAULT_MASTER_OPTS["ssh_sudo"] + ), +@@ -557,7 +569,7 @@ class SSH(MultiprocessingStateMixin): + mods=self.mods, + fsclient=self.fsclient, + thin=self.thin, +- **target ++ **target, + ) + if salt.utils.path.which("ssh-copy-id"): + # we have ssh-copy-id, use it! +@@ -573,7 +585,7 @@ class SSH(MultiprocessingStateMixin): + mods=self.mods, + fsclient=self.fsclient, + thin=self.thin, +- **target ++ **target, + ) + stdout, stderr, retcode = single.cmd_block() + try: +@@ -601,7 +613,7 @@ class SSH(MultiprocessingStateMixin): + fsclient=self.fsclient, + thin=self.thin, + mine=mine, +- **target ++ **target, + ) + ret = {"id": single.id} + stdout, stderr, retcode = single.run() +@@ -1022,7 +1034,10 @@ class Single: + remote_port_forwards=None, + winrm=False, + ssh_options=None, +- **kwargs ++ keepalive=True, ++ keepalive_interval=60, ++ keepalive_count_max=3, ++ **kwargs, + ): + # Get mine setting and mine_functions if defined in kwargs (from roster) + self.mine = mine +@@ -1081,6 +1096,9 @@ class Single: + "priv": priv, + "priv_passwd": priv_passwd, + "timeout": timeout, ++ "keepalive": keepalive, ++ "keepalive_interval": keepalive_interval, ++ "keepalive_count_max": keepalive_count_max, + "sudo": sudo, + "tty": tty, + "mods": self.mods, +@@ -1302,7 +1320,7 @@ class Single: + self.id, + fsclient=self.fsclient, + minion_opts=self.minion_opts, +- **self.target ++ **self.target, + ) + + opts_pkg = pre_wrapper["test.opts_pkg"]() # pylint: disable=E1102 +@@ -1388,7 +1406,7 @@ class Single: + self.id, + fsclient=self.fsclient, + minion_opts=self.minion_opts, +- **self.target ++ **self.target, + ) + wrapper.fsclient.opts["cachedir"] = opts["cachedir"] + self.wfuncs = salt.loader.ssh_wrapper(opts, wrapper, self.context) +diff --git a/salt/client/ssh/client.py b/salt/client/ssh/client.py +index 0b67598fc6..a00f5de423 100644 +--- a/salt/client/ssh/client.py ++++ b/salt/client/ssh/client.py +@@ -52,6 +52,9 @@ class SSHClient: + ("ssh_priv_passwd", str), + ("ssh_identities_only", bool), + ("ssh_remote_port_forwards", str), ++ ("ssh_keepalive", bool), ++ ("ssh_keepalive_interval", int), ++ ("ssh_keepalive_count_max", int), + ("ssh_options", list), + ("ssh_max_procs", int), + ("ssh_askpass", bool), +@@ -108,7 +111,15 @@ class SSHClient: + return sane_kwargs + + def _prep_ssh( +- self, tgt, fun, arg=(), timeout=None, tgt_type="glob", kwarg=None, context=None, **kwargs ++ self, ++ tgt, ++ fun, ++ arg=(), ++ timeout=None, ++ tgt_type="glob", ++ kwarg=None, ++ context=None, ++ **kwargs + ): + """ + Prepare the arguments +diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py +index bc1ad034df..182e2c19e3 100644 +--- a/salt/client/ssh/shell.py ++++ b/salt/client/ssh/shell.py +@@ -85,6 +85,9 @@ class Shell: + remote_port_forwards=None, + winrm=False, + ssh_options=None, ++ keepalive=True, ++ keepalive_interval=None, ++ keepalive_count_max=None, + ): + self.opts = opts + # ssh , but scp [ (4, 9): + options.append("GSSAPIAuthentication=no") + options.append("ConnectTimeout={}".format(self.timeout)) ++ if self.keepalive: ++ options.append(f"ServerAliveInterval={self.keepalive_interval}") ++ options.append(f"ServerAliveCountMax={self.keepalive_count_max}") + if self.opts.get("ignore_host_keys"): + options.append("StrictHostKeyChecking=no") + if self.opts.get("no_host_keys"): +@@ -165,6 +174,9 @@ class Shell: + if self.opts["_ssh_version"] > (4, 9): + options.append("GSSAPIAuthentication=no") + options.append("ConnectTimeout={}".format(self.timeout)) ++ if self.keepalive: ++ options.append(f"ServerAliveInterval={self.keepalive_interval}") ++ options.append(f"ServerAliveCountMax={self.keepalive_count_max}") + if self.opts.get("ignore_host_keys"): + options.append("StrictHostKeyChecking=no") + if self.opts.get("no_host_keys"): +diff --git a/salt/config/__init__.py b/salt/config/__init__.py +index d8258a4dbc..68f2b0f674 100644 +--- a/salt/config/__init__.py ++++ b/salt/config/__init__.py +@@ -822,6 +822,9 @@ VALID_OPTS = immutabletypes.freeze( + "ssh_scan_ports": str, + "ssh_scan_timeout": float, + "ssh_identities_only": bool, ++ "ssh_keepalive": bool, ++ "ssh_keepalive_interval": int, ++ "ssh_keepalive_count_max": int, + "ssh_log_file": str, + "ssh_config_file": str, + "ssh_merge_pillar": bool, +@@ -1592,6 +1595,9 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze( + "ssh_scan_ports": "22", + "ssh_scan_timeout": 0.01, + "ssh_identities_only": False, ++ "ssh_keepalive": True, ++ "ssh_keepalive_interval": 60, ++ "ssh_keepalive_count_max": 3, + "ssh_log_file": os.path.join(salt.syspaths.LOGS_DIR, "ssh"), + "ssh_config_file": os.path.join(salt.syspaths.HOME_DIR, ".ssh", "config"), + "cluster_mode": False, +diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py +index dc125de7d7..6c7f9f2f66 100644 +--- a/salt/utils/parsers.py ++++ b/salt/utils/parsers.py +@@ -3383,6 +3383,25 @@ class SaltSSHOptionParser( + "-R parameters." + ), + ) ++ ssh_group.add_option( ++ "--disable-keepalive", ++ default=True, ++ action="store_false", ++ dest="ssh_keepalive", ++ help=( ++ "Disable KeepAlive probes (ServerAliveInterval) for the SSH connection." ++ ), ++ ) ++ ssh_group.add_option( ++ "--keepalive-interval", ++ dest="ssh_keepalive_interval", ++ help=("Define the value for ServerAliveInterval option."), ++ ) ++ ssh_group.add_option( ++ "--keepalive-count-max", ++ dest="ssh_keepalive_count_max", ++ help=("Define the value for ServerAliveCountMax option."), ++ ) + ssh_group.add_option( + "--ssh-option", + dest="ssh_options", +diff --git a/tests/pytests/unit/client/ssh/test_single.py b/tests/pytests/unit/client/ssh/test_single.py +index c88a1c2127..8d87da8700 100644 +--- a/tests/pytests/unit/client/ssh/test_single.py ++++ b/tests/pytests/unit/client/ssh/test_single.py +@@ -63,6 +63,61 @@ def test_single_opts(opts, target): + **target, + ) + ++ assert single.shell._ssh_opts() == "" ++ expected_cmd = ( ++ "ssh login1 " ++ "-o KbdInteractiveAuthentication=no -o " ++ "PasswordAuthentication=yes -o ConnectTimeout=65 -o ServerAliveInterval=60 " ++ "-o ServerAliveCountMax=3 -o Port=22 " ++ "-o IdentityFile=/etc/salt/pki/master/ssh/salt-ssh.rsa " ++ "-o User=root date +%s" ++ ) ++ assert single.shell._cmd_str("date +%s") == expected_cmd ++ ++ ++def test_single_opts_custom_keepalive_options(opts, target): ++ """Sanity check for ssh.Single options with custom keepalive""" ++ ++ single = ssh.Single( ++ opts, ++ opts["argv"], ++ "localhost", ++ mods={}, ++ fsclient=None, ++ thin=salt.utils.thin.thin_path(opts["cachedir"]), ++ mine=False, ++ keepalive_interval=15, ++ keepalive_count_max=5, ++ **target, ++ ) ++ ++ assert single.shell._ssh_opts() == "" ++ expected_cmd = ( ++ "ssh login1 " ++ "-o KbdInteractiveAuthentication=no -o " ++ "PasswordAuthentication=yes -o ConnectTimeout=65 -o ServerAliveInterval=15 " ++ "-o ServerAliveCountMax=5 -o Port=22 " ++ "-o IdentityFile=/etc/salt/pki/master/ssh/salt-ssh.rsa " ++ "-o User=root date +%s" ++ ) ++ assert single.shell._cmd_str("date +%s") == expected_cmd ++ ++ ++def test_single_opts_disable_keepalive(opts, target): ++ """Sanity check for ssh.Single options with custom keepalive""" ++ ++ single = ssh.Single( ++ opts, ++ opts["argv"], ++ "localhost", ++ mods={}, ++ fsclient=None, ++ thin=salt.utils.thin.thin_path(opts["cachedir"]), ++ mine=False, ++ keepalive=False, ++ **target, ++ ) ++ + assert single.shell._ssh_opts() == "" + expected_cmd = ( + "ssh login1 " +diff --git a/tests/pytests/unit/client/ssh/test_ssh.py b/tests/pytests/unit/client/ssh/test_ssh.py +index cece16026c..23223ba8ec 100644 +--- a/tests/pytests/unit/client/ssh/test_ssh.py ++++ b/tests/pytests/unit/client/ssh/test_ssh.py +@@ -78,6 +78,9 @@ def roster(): + ("ssh_scan_ports", "test", True), + ("ssh_scan_timeout", 1.0, True), + ("ssh_timeout", 1, False), ++ ("ssh_keepalive", True, True), ++ ("ssh_keepalive_interval", 30, True), ++ ("ssh_keepalive_count_max", 3, True), + ("ssh_log_file", "/tmp/test", True), + ("raw_shell", True, True), + ("refresh_cache", True, True), +-- +2.42.0 + + diff --git a/salt.changes b/salt.changes index f450ff3..f2c10a1 100644 --- a/salt.changes +++ b/salt.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Fri Dec 1 11:04:02 UTC 2023 - Pablo Suárez Hernández + +- Enable "KeepAlive" probes for Salt SSH executions (bsc#1211649) + +- Added: + * enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch + ------------------------------------------------------------------- Thu Nov 16 10:33:00 UTC 2023 - Pablo Suárez Hernández diff --git a/salt.spec b/salt.spec index 55f5e04..c4dea34 100644 --- a/salt.spec +++ b/salt.spec @@ -327,6 +327,8 @@ Patch89: fix-gitfs-__env__-and-improve-cache-cleaning-bsc-119.patch Patch90: dereference-symlinks-to-set-proper-__cli-opt-bsc-121.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/614 (revert patch 77) Patch91: revert-make-sure-configured-user-is-properly-set-by-.patch +# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65488 +Patch92: enable-keepalive-probes-for-salt-ssh-executions-bsc-.patch ### IMPORTANT: The line below is used as a snippet marker. Do not touch it. ### SALT PATCHES LIST END