Bug 8232 - vsm extproc handling relies on deprecated asyncore
Summary: vsm extproc handling relies on deprecated asyncore
Status: CLOSED FIXED
Alias: None
Product: ThinLinc
Classification: Unclassified
Component: Other (show other bugs)
Version: trunk
Hardware: PC Unknown
: P2 Normal
Target Milestone: 4.16.0
Assignee: Linn
URL:
Keywords: adaha_tester, relnotes, samuel_tester
Depends on:
Blocks: 7636
  Show dependency treegraph
 
Reported: 2023-09-20 10:11 CEST by Linn
Modified: 2023-12-29 14:27 CET (History)
3 users (show)

See Also:
Acceptance Criteria:
MUST: * Code changes should be compatible with Python 3.4.4 (same version as SLES 12 has) * Replace asyncore with asyncio SHOULD: * Keep the same base functionality from extproc - Should be able to run scripts in a subprocess - Receive the output from the subprocess - Run a callback function on the output on subprocess exit - Scripts should be able to receive input from stdin EXTRA: * Redundant code should be removed.


Attachments

Description Linn cendio 2023-09-20 10:11:00 CEST
Broken out from bug 7636. See that bug for details.

Extproc is our handling of asynchronously running subprocesses. We want these to use asyncio instead.
Comment 1 Linn cendio 2023-09-20 10:26:31 CEST
The base class AsyncProcess is used by four subclasses, listed below. The main functionality for all subclasses seems to be to start a subprocess, run a script and handle any output piped back from the subprocess.

* GetUserGroups
* SessionStartupProcess
* ReturnCodeStdoutStderrProcess
* InputReturnCodeStdoutStderrProcess
Comment 2 Linn cendio 2023-09-20 13:07:48 CEST
Investigated how the subclasses are used, and found a way to check the usage of each subclass.

GetUserGroups
-------------
handler_getusersessions.py - Get a list of sessions, e.g. the list of sessions when multiple sessions are enabled.
handler_newsession.py - Start a new session.
handler_shadowsession.py - Shadow a user.

SessionStartupProcess
---------------------
loginhandler_common.py - Running e.g. xstartup scripts

ReturnCodeStdoutStderrProcess
-----------------------------
handler_unbindports.py - Handle unbind of ports, seen when starting a new session.
handler_verifysessions.py - Seems to verify all running sessions. Is run when starting a new session.

InputReturnCodeStdoutStderrProcess
----------------------------------
licensehandler.py - Send mail warning about license usage.
Comment 3 Alexander Zeijlon cendio 2023-09-28 09:07:54 CEST
The asyncio equivalent of our AsyncProcess, consists of two parts:

* A SubprocessProtocol class, which is responsible for deciding what needs to be
  transmitted, and how to handle received data.
* A SubprocessTransport class, which is responsible for how data is transmitted,
  e.g. as a wrapper for a TCP-socket connection.

The dataflow between our components and a subprocess would look something like this:
[Server code] ⇿ [SubprocessProtocol] ⇿ [SubprocessTransport] ⇿ [Subprocess]
Comment 4 Linn cendio 2023-10-12 16:10:11 CEST
Our first idea to replace asyncore was to build our own protocol. This would make sure that we did not use the async/await keywords and as such would keep the Python requirement to version 3.4.4. We did try this solution out, using a custom protocol and as well as a transport provided by Python. While this solution worked, it meant that we needed to take care of lowlevel protocol stuff, and ideally we would like to be on a higher level of abstraction instead.

We also found coroutine asyncio.create_subprocess_exec(), which handles the protocol and transport on its own internally. However, since it is a coroutine, and coroutines seemed to be linked closely to the async/await keywords, we did not think this function would be an option for us in 3.4.4. We were wrong about that assumption though. Coroutines aren't limited to usage with only async/await. When used in combination with ensure_future() they can be used on Python 3.4.4 as well.

Using create_subprocess_exec() is on a more suitable abstraction level than using a custom protocol, so this is the path we will go.
Comment 5 Linn cendio 2023-10-12 16:29:40 CEST
When making the switch to asyncio, we can remove quite a bit of the complexity in extproc since asyncio implicitly takes care of most of the things we had to handle manually in our async processes. E.g., we no longer have to make sure that the process is killed even if it got an exception.

Also, asyncore was designed with subclassing in mind, but asyncio is not. That means that we can remove the previous subclasses and mainly replace them with one core function (perhaps along with some functions more niched to the functionality of each subclass). The idea is that this core function should use create_subprocess_exec() and as a whole should behave similarly to subprocess.run() to make it recognisable and more intuitive to use.
Comment 6 Alexander Zeijlon cendio 2023-10-13 09:05:03 CEST
Each public function in extproc should return an asyncio.Future that can be awaited [1] by the caller. In our implementation, we have to chain several futures internally, where chaining means that we e.g. need to wait for both future A and future B, where the result set on A is needed by B, such that B depends on A.

[1] Either through usage of the await-syntax or by using asyncio.ensure_future.

Currently, Python has no built-in way of smoothly handling dependencies between futures, but the chaining is mostly straightforward - the dependency-chain is achieved with callback functions on the futures. Continuing on the example with futures A and B, if B depends on the result of A, then the result of B needs to be computed in a callback of A.

This also means that we need to handle cancellation for the same dependency-chain, where if the outer future, returned to the caller is cancelled, we need to propagate this cancellation to any inner futures, created internally by the called function. Cancellation can occur if e.g. the caller adds a timeout to the outer future with asyncio.wait_for.
Comment 19 Alexander Zeijlon cendio 2023-10-23 14:55:01 CEST
If the future returned from subprocess_run is cancelled, e.g. by asyncio.wait_for, we need to make sure that the running process is terminated.

This can be done as soon as the process-object becomes available in one of the internal callbacks of subprocess_run, after the call to create_subprocess_exec has finished.

One way to achieve this would be to attach a terminate-callback-function on the output future from subprocess_run, where if the output is cancelled, we immediately call terminate() on the process.
Comment 25 Linn cendio 2023-10-25 11:34:41 CEST
When adding support for text mode to subprocess_run() we tried to mimic how Pythons subprocess.Popen handles text mode (link to docs for Popen [1]).

To trigger text mode, any of the following arguments can be used:
 - text
 - universal_newlines (alias of text)
 - encoding
 - errors

If errors are not specified, the default error handling of encode/decode should be used. If encoding isn't specified, this is how Popen behaves since Python 3.11:
> if sys.flags.utf8_mode:
>     return "utf-8"
> else:
>     return locale.getencoding()
From the documentation of getencoding() [2]:
> This function is similar to getpreferredencoding(False) except this function 
> ignores the Python UTF-8 Mode.
Seeing that Popen explicitly respects Python's UTF-8 mode, the if-case above could be replaced with a call directly to getpreferredencoding(False).

I wasn't able to find the default encoding for Popen before Python 3.11, but the commit [3] that added getencoding() to Popen does not mention any changes to locale defaults. This makes me suspect that getpreferredencoding() is what was previously used.

[1]: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
[2]: https://docs.python.org/3/library/locale.html#locale.getpreferredencoding
[3]: https://github.com/python/cpython/commit/354ace8b07e7d445fd2de713b6af1271536adce0
Comment 26 Alexander Zeijlon cendio 2023-10-25 13:03:59 CEST
Follow-up on comment #19.

The old AsyncProcess implementation killed processes on timeout in the following way:
1. terminate the process with os.kill(pid, signal.SIGTERM)
2. close file descriptors (fd) / pipes, connected to the process by:
   - Closing each file descriptors with os.close(fd)
   - Disassociating the file descriptor with the asyncbase event-loop.

Ideally, we want equivalent timeout handling in the new implementation to keep the behavior consistent between ThinLinc server releases. The equivalent of point two, above, seems to be to call close() on the pipe-transports, contained within the process-object that is generated by asyncio.create_subprocess_exec.

It turns out that this is hard to achieve in a robust way, since these transports need to be accessed through a private variable on the process-object. And we do not want to access private variables, since these are more likely to change between Python releases, possibly without deprecation warnings beforehand.
Comment 27 Alexander Zeijlon cendio 2023-10-25 13:51:11 CEST
The file descriptors / pipes in question are stdin(0), stdout(1) and stderr(2).
Comment 28 Alexander Zeijlon cendio 2023-10-26 16:21:17 CEST
The current timeout behavior is to terminate the process, but to not handle any of its children if they exist. These can still hold on to the pipes, which essentially keeps the pipes open until all children have exited.

Hence, another possibility for making sure the pipes are closed would be to ensure that the process and all its children terminate when the timeout occurs.

But this would make the behavior of subprocess_run diverge from AsyncProcess, which means that it is outside the scope of this bug.

Bug 8245 discusses this further.
Comment 29 Alexander Zeijlon cendio 2023-10-26 16:51:57 CEST
The final option is to handle pipe closing through the StreamWriter/StreamReader objects, accessible directly on the process object, which reference the pipe-transports internally.

These are:
* stdin  : StreamWriter
* stdout : StreamReader
* stderr : StreamReader

Unfortunately, only stdin has a close()-method, which causes the stdin-pipe to close. The other two, stdout and stderr, have a feed_eof()-method, which causes the corresponding pipe-transports to close as a side effect. Furthermore, feed_eof() is not documented, and it is likely that it should be treated as a private function.

This means that we can only close the stdin-pipe in a robust way, and we are therefore leaving the stdout- and stderr-pipes open until all children of the process exit.

For timeout handling, subprocess_run is therefore not a one-to-one replacement for its successor AsyncProcess.
Comment 37 Linn cendio 2023-10-27 16:09:09 CEST
Tested the functionality of extproc on Ubuntu 22.04 through the different use cases described in comment 2. Note that some of the logging is done is vsmserver.log and some of it in vsmagent.log.

 * handler_getusersessions.py
Enabled multiple sessions per user to see the list of available sessions when logging in. Could also see this line in the log:
> DEBUG vsmserver: GetUserSessionHandler: List of groups: [1024]
 * handler_newsession.py
Started a new session and saw this line in the log:
> DEBUG vsmserver: List of groups: [1024]
 * handler_shadowsession.py
Shadowed a user. Was able to successfully shadow if shadower had correct permissions, and was denied access if shadower was not allowed.
> DEBUG vsmserver: ShadowSessionHandler: List of groups: [1000, 10]
 * loginhandler_common.py
Added a startupscript in both /opt/thinlinc/etc/sessionstartup.d and /opt/thinlinc/etc/sessionreconnect.d and could see the script writing to both stdout and stderr. Logging found in vsmserver.log.

 * handler_unbindports.py
Handle unbind of ports, seen when starting a new session in vsmagent.log
> DEBUG2 vsmagent: Handling method unbind_ports
> DEBUG3 vsmagent: ss output: State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
 * handler_verifysessions.py
Is run when starting a new session. This handler has no logging when things go well, but this line in vsmagent.log indicates that it is being called:
> DEBUG2 vsmagent: Handling method verify_sessions
 * licensehandler.py
Sends a mail warning about license usage. Replaced /usr/sbin/sendmail with my own bash script and could see that it was called with the expected arguments and stdin value.
To see the stdin data, I used 'cat -' and piped the output to a file. To trigger the send mail command, I created the file /var/lib/vsm/license.messages and filled it with some text (to imitate license warnings), and when restarting vsmserver sendmail was run.
Comment 38 Linn cendio 2023-10-27 16:17:45 CEST
Tested the acceptance criteria:

> MUST:
> * Code changes must be compatible with Python 3.6
> 
> SHOULD:
> * Code changes should be compatible with Python 3.4
Tested briefly running on SLES 12 which has 3.4.4, and saw that the handlers running when logging in to a session works well. Futher, the unit tests are run in Python 3.6 and passed without issues.


> SHOULD:
> * Use asyncio in extproc instead of asyncbase
Yes, all calls to asyncbase have been removed or replaced to direct asyncio calls


> * Keep the same base functionality from extproc
>   - Should be able to run scripts in a subprocess
>   - Receive the output from the subprocess
>   - Run a callback function on the output on subprocess exit
The handlers that use extproc works the same after moving to async io, see comment 37 for more details


> EXTRA:
> * Redundant code should be removed.
Yes, code for things that are handled internally by asyncio was removed. Further, a few of the previous subclasses could be merged and replaced by a single function, removing unnecessary complexity.


Tips for tester
---------------
Test more in depth on a platform with Python 3.4, to see that every aspect of extproc works as intended.
Comment 42 Samuel Mannehed cendio 2023-11-10 16:35:31 CET
Tested server build 3416 on Fedora 39 (with Python 3.12):

✓ New session
  ✓ Connecting works
  ✓ Startup scripts in sessionstartup.d are executed if set up correctly
  ✓ Startup scripts in sessionstartup.d are not executed when setup incorrectly
    ✓ no execute (+x) permission
    ✓ no hashbang in script
✓ Reconnecting to an existing session
  ✓ Connecting works
  ✓ Reconnect scripts in sessionreconnect.d are executed if set up correctly
✓ Shadowing
  ✓ Connecting as shadower works if permissions are set up
  ✓ Shadower is denied if not part of 'shadowers'
  ✓ Shadower question and notifications work 
✓ Multiple sessions
  ✓ Starting a second session for the same user works
  ✓ Reconnecting to a different session works
  ✓ Terminating a session from the session list works
✓ License warnings
  ✓ 10 sessions are started without issue, the 11th session is blocked "Cannot allocate license"
  ✓ A warning is sent to the admin_email address, given that sendmail is configured correctly
✓ No errors in vsmserver or vsmagent logs aside from those reported on bug 7636
✓ Error handling
  ✓ A broken /usr/sbin/ss causes the master to mark the agent as DOWN
  ✓ No unexpected errors in logs
Comment 43 Linn cendio 2023-11-13 09:01:16 CET
Updated acceptance critera:

Clarfiy that the targeted Python version is 3.4.4., which the same version that SLES 12 currently uses. This should mean that we do not drop support for any of our currently targeted platforms.

Clarify that we want to stop using asyncore in favour of using asyncio.
Comment 44 Adam Halim cendio 2023-11-13 09:42:22 CET
Tested build r40579 on SLES 12 (Python 3.4.10):

* handler_newsession.py:
Created a new session and saw this in the log:
> 2023-11-07 10:37:48 DEBUG vsmserver: List of groups: [100]

* handler_getusersessions.py:
I set max_sessions_per_user=3 and tested the following:

1. Create a new session when no other sessions are running.
2. Hijack the session created in 1.
3. Create a second session.
4. Hijack session created in 3.
5. Create a third session.
6. Hijack session created in 5. 
7. From the client, end all three sessions.

The following line was logged every time the available sessions list was displayed on the client:
> 2023-11-07 10:36:21 DEBUG vsmserver: GetUserSessionHandler: List of groups: [100]

* handler_shadowsession.py:
I was able to shadow another user without issue after being given permission. Without permission, access was denied.
> 2023-11-07 10:40:08 DEBUG vsmserver: ShadowSessionHandler: List of groups: [100]

* loginhandler_common.py:
Added two scripts to /opt/thinlinc/etc/sessionstartup.d/ and /opt/thinlinc/etc/sessionreconnect.d/ and could see that both scripts wrote to stdout, stderr, and returned an exit code. All of this could be seen in vsmserver.log.
The return code is only logged if it was non-zero, but stdout and stderr are logged regardless of return code (see bug 8248).

* handler_unbindports.py
The following log is seen in vsmagent.log when creating a new session:
> 2023-11-07 10:54:26 DEBUG2 vsmagent: Handling method unbind_ports from ('127.0.0.1', 1023)
> 2023-11-07 10:54:26 DEBUG3 vsmagent: ss output: State      Recv-Q Send-Q Local Address:Port               Peer Address:Port
> 
> 
Not sure why, but I got some weird spacing in the log and two blank newlines at the end.

* handler_verifysessions.py
This is logged when a new session is created.
> 2023-11-07 10:59:16 DEBUG2 vsmagent: Handling method verify_sessions from ('127.0.0.1', 1023)

* licensehandler.py
Did the same thing as in comment 37 and got the same results.


There are four cases where we use extproc:
1. ss
2. sendmail
3. tl-sesssion
4- user-scripts (session start/reconnect)

As ss and sendmail can differ between systems, I decided to test them (as well as user scripts).

* ss
Removing ss from the system crashes vsmagent during startup with the following message in journalctl:
> -- Unit vsmagent.service has begun starting up.
> Nov 07 14:33:16 lab-170 bash[3624]: ss is missing.
> Nov 07 14:33:16 lab-170 systemd[1]: vsmagent.service: Control process exited, code=exited status=1
> Nov 07 14:33:16 lab-170 systemd[1]: Failed to start ThinLinc VSM agent.
> -- Subject: Unit vsmagent.service has failed

Replacing ss with a script that does nothing but write to stdout and stderr, regardless of exit status, gives the following log messages:
> 2023-11-07 15:37:40 DEBUG2 vsmagent: Handling method verify_sessions from ('127.0.0.1', 1022)
> 2023-11-07 15:37:40 WARNING vsmagent: ss wrote to stderr: writing to stderr
>  
> 2023-11-07 15:37:40 WARNING vsmagent: unable to parse ss line: 'writing to stdout'
Not sure why there is a trailing newline after writing to stderr.

Replacing ss with a script that does nothing but write to stdout and stderr, gives the following log messages regardless of exit status:
> 2023-11-07 15:37:40 DEBUG2 vsmagent: Handling method verify_sessions from ('127.0.0.1', 1022)
> 2023-11-07 15:37:40 WARNING vsmagent: ss wrote to stderr: writing to stderr
> 
> 2023-11-07 15:37:40 WARNING vsmagent: unable to parse ss line: 'writing to stdout'

Changing the script so that it does nothing but exit 0:
> 2023-11-07 15:42:26 DEBUG2 vsmagent: Handling method unbind_ports from ('127.0.0.1', 1023)
> 2023-11-07 15:42:26 DEBUG3 vsmagent: ss output:

I changed the script to be a wrapper for ss, but added a sleep.
Making the script to sleep for <40 seconds before calling ss (I tested with 30 seconds) will make the client hang for 30 seconds each time verify_sessions is run, but there are no other consequences.

With the sleep is set to >40 seconds (I tested with 100 seconds), I was unable to create a new session (agent status unreachable) and got the following in the log:
> 2023-11-07 15:58:07 ERROR vsmagent: Exception in callback ServerProtocol._callback_done(<Future cancelled>)
> 2023-11-07 15:58:07 ERROR vsmagent: handle: <Handle ServerProtocol._callback_done(<Future cancelled>)>
> 2023-11-07 15:58:07 ERROR vsmagent: ----------------------------------------
> 2023-11-07 15:58:07 ERROR vsmagent: Traceback (most recent call last):
> 2023-11-07 15:58:07 ERROR vsmagent:   File "/usr/lib64/python3.4/asyncio/events.py", line 125, in _run
> 2023-11-07 15:58:07 ERROR vsmagent:     self._callback(*self._args)
> 2023-11-07 15:58:07 ERROR vsmagent:   File "/opt/thinlinc/modules/thinlinc/vsm/xmlrpc.py", line 348, in _callback_done
> 2023-11-07 15:58:07 ERROR vsmagent:     assert future is self . _response
> 2023-11-07 15:58:07 ERROR vsmagent: AssertionError
> 2023-11-07 15:58:07 ERROR vsmagent: ----------------------------------------

* sendmail
Removing sendmail from the system causes the following message to be logged during startup:
> 2023-11-07 17:36:46 ERROR vsmserver.license: No sendmail found. No way to send warnings about license trouble:
> 2023-11-07 17:36:46 ERROR vsmserver.license: From: ThinLinc on lab-170 <thinlinc@lab-170>...

Replacing /usr/sbin/sendmail in the same way as described in comment 37 will only log a warning in vsmserver.log if sendmail returns a non-zero value and ignores stdout and stderr if it returns with 0 (see bug 8248).

Adding a 30-second sleep to the script will simply delay sending the email by 30 seconds, but the system is responsive meanwhile.
I tried using a 100-second delay as well and saw no difference / any timeouts.

* user-scripts
In addition to the tests done performed for loginhandler_common.py described previously, I tried adding a 30-second delay to a user script in /opt/thinlinc/sessionstartup.d/. This simply made the client wait for 30 seconds during login, but otherwise kept the server responsive. Changing the delay to 100 seconds had no unexpected side effects.

I performed the same tests for build 4.15.0 and saw the following differences:
 
* loginhandler_common.py:
In this case, the return code was also logged regardless of exit status.

* ss
Adding a delay >40 seconds (I tested with 100 seconds) did not raise any exceptions that could be seen in the logs.

All commits have been reviewed, and they looked good. The code has been tested on both SLES 12 (Python 3.4.10) and Fedora 39 (Python 3.12) and works on them both. A comparison to 4.15.0 was also made, and no major differences were observed.

Acceptance criteria:
MUST:
* Code changes should be compatible with Python 3.4.4 (same version as SLES 12 has) ✅

* Replace asyncore with asyncio ✅

SHOULD:
* Keep the same base functionality from extproc ✅
  - Should be able to run scripts in a subprocess ✅
  - Receive the output from the subprocess ✅
  - Run a callback function on the output on subprocess exit ✅
  - Scripts should be able to receive input from stdin ✅

EXTRA:
* Redundant code should be removed. ✅

Note that the code was tested using Python 3.4.10 and not Python 3.4.4, as that was the version my machine running SLES 12 had installed.

Closing as all acceptance criteria are met.
Comment 45 Alexander Zeijlon cendio 2023-11-22 09:03:47 CET
Reopening for some minor fixes.
Comment 48 Alexander Zeijlon cendio 2023-11-23 08:52:36 CET
Removed logging from get_user_gruops() that only happens in a scenario, that is very unlikely in a real world use case.
Comment 49 Adam Halim cendio 2023-11-27 12:36:37 CET
Looks good! Closing.
Comment 55 Pierre Ossman cendio 2023-12-21 13:55:38 CET
The error logging has unfortunately regressed after changing this bug. With a missing tl-session, I get this with 4.15.0:

> 2023-12-21 13:53:41 ERROR vsmserver.extproc: OSError: "[Errno 2] No such file or directory: '/opt/thinlinc/libexec/tl-session'" when trying to start /opt/thinlinc/libexec/tl-session

With the current builds I just get:

> 2023-12-21 13:52:07 WARNING vsmserver.session: Exception when getting user groups: <class 'FileNotFoundError'>
Comment 57 Samuel Mannehed cendio 2023-12-21 15:51:27 CET
Comment 55 is fixed now.
Comment 58 Pierre Ossman cendio 2023-12-22 14:31:58 CET
Looks good. I now get:

> 2023-12-22 14:19:07 WARNING vsmserver.session: Exception when getting user groups: [Errno 2] No such file or directory: '/opt/thinlinc/libexec/tl-session'

Tested all three cases where this problem existed. Could not see that any case was overlooked.
Comment 59 Adam Halim cendio 2023-12-29 10:51:17 CET
Ran into an issue with build 3457 on SLES12. These issues did not appear when running build 3457 on Fedora 38, or on SLES12 running build 4.15.0.

Added a simple script to sessionstartup.d/ and sessionreconnect.d/ but forgot to make it executeable, which gives the following error in the log:
> 2023-12-29 10:09:04 ERROR vsmserver: Exception when running /opt/thinlinc/etc/sessionstartup.d/test_2.sh: [Errno 13] Permission denied
Whenever I tried to make a new connection or restarted the server, I got ResourceWarnings.

Restart/shutdown:
> 2023-12-29 10:17:50 INFO vsmserver: Terminating. Have a nice day!
> sys:1: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
> sys:1: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
I got different traces when reconnecting and selecting from session list  (seemingly random)

Reconnections:
> 2023-12-29 10:16:33 INFO vsmserver.session: User with uid 1000 requested a reconnection to 127.0.0.1:10
> 2023-12-29 10:16:33 INFO vsmserver: Verifying session 127.0.0.1:10 for cendio
> 2023-12-29 10:16:33 INFO vsmserver: Session 127.0.0.1:10 for cendio is alive and ready for reconnection
> 2023-12-29 10:16:33 ERROR vsmserver: Exception when running /opt/thinlinc/etc/sessionreconnect.d/test_2.sh: [Errno 13] Permission denied
> /usr/lib64/python3.4/email/_header_value_parser.py:204: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return ''.join(x.value for x in self if x.value)
> /usr/lib64/python3.4/email/_header_value_parser.py:204: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return ''.join(x.value for x in self if x.value)

> 2023-12-29 10:20:44 ERROR vsmserver: Exception when running /opt/thinlinc/etc/sessionreconnect.d/test_2.sh: [Errno 13] Permission denied
> /usr/lib64/python3.4/email/_header_value_parser.py:192: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   super().__init__(*args, **kw)
> /usr/lib64/python3.4/email/_header_value_parser.py:192: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   super().__init__(*args, **kw)

> 2023-12-29 10:23:09 ERROR vsmserver: Exception when running /opt/thinlinc/etc/sessionstartup.d/test_2.sh: [Errno 13] Permission denied
> /usr/lib64/python3.4/selectors.py:182: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   raise KeyError("{!r} is not registered".format(fileobj)) from None
> /usr/lib64/python3.4/selectors.py:182: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   raise KeyError("{!r} is not registered".format(fileobj)) from None

> 2023-12-29 10:24:34 ERROR vsmserver: Exception when running /opt/thinlinc/etc/sessionreconnect.d/test_2.sh: [Errno 13] Permission denied
> /usr/lib64/python3.4/email/_header_value_parser.py:208: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return sum((x.all_defects for x in self), self.defects)
> /usr/lib64/python3.4/email/_header_value_parser.py:208: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return sum((x.all_defects for x in self), self.defects)

> 2023-12-29 10:26:19 INFO vsmserver.session: User with uid 1000 (cendio) requested a new session
> /usr/lib64/python3.4/enum.py:228: ResourceWarning: unclosed <socket.socket fd=11, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return cls.__new__(cls, value)
> /usr/lib64/python3.4/enum.py:228: ResourceWarning: unclosed <socket.socket fd=12, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>
>   return cls.__new__(cls, value)
Comment 60 Adam Halim cendio 2023-12-29 14:27:03 CET
(In reply to Adam Halim from comment #59)
> Ran into an issue with build 3457 on SLES12. These issues did not appear
> when running build 3457 on Fedora 38, or on SLES12 running build 4.15.0.
This bug was fixed in Python 3.8: https://github.com/python/cpython/issues/79902 and it doesn't seem possible to work around it completely. A more general bug about this issue has been moved to bug 8278.

Note You need to log in before you can comment on or make changes to this bug.