Merge ~sylvain-pineau/checkbox-ng:fix-1841702 into checkbox-ng:master

Proposed by Sylvain Pineau
Status: Rejected
Rejected by: Sylvain Pineau
Proposed branch: ~sylvain-pineau/checkbox-ng:fix-1841702
Merge into: checkbox-ng:master
Diff against target: 72 lines (+4/-37)
1 file modified
plainbox/impl/execution.py (+4/-37)
Reviewer Review Type Date Requested Status
Maciej Kisielewski (community) Disapprove
Checkbox Developers Pending
Review via email: mp+372452@code.launchpad.net

Description of the change

Fixes the linked bug.

The new unified runner introduced and intermediate player, stdin_forwarder() which creates a deadlock with commands like:

$ more foo | cat

The proposed patch is using a method originally found in RootViaSudoWithPassExecutionController->execute_job() [1]

[1] can be found in the last stable release: https://launchpad.net/checkbox-ng/trunk/1.4.0/+download/checkbox-ng-1.4.0.tar.gz

Maciej, could you please check I'm not breaking remote features by annihilating this stdin_forwarder()?

To post a comment you must log in.
Revision history for this message
Maciej Kisielewski (kissiel) wrote :

stdin is not only for supplying password, but also for sending input to jobs that read stdin.
Like collect manifest for instance. So we need the red bit, I'm affraid.

review: Disapprove

Unmerged commits

f03ad1e... by Sylvain Pineau

execution: Use proc.communicate() to supply password

The additional pipe creates a deadlock with commands like:

$ more foo | cat

Fixes: lp:1841702

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/plainbox/impl/execution.py b/plainbox/impl/execution.py
index 01e783f..740d4e7 100644
--- a/plainbox/impl/execution.py
+++ b/plainbox/impl/execution.py
@@ -182,45 +182,12 @@ class UnifiedRunner(IJobRunner):
182182
183 def call(extcmd_popen, *args, **kwargs):183 def call(extcmd_popen, *args, **kwargs):
184 """Handle low-level subprocess stuff."""184 """Handle low-level subprocess stuff."""
185 is_alive = True
186 # Notify that the process is about to start185 # Notify that the process is about to start
187 extcmd_popen._delegate.on_begin(args, kwargs)186 extcmd_popen._delegate.on_begin(args, kwargs)
188 # Setup stdout/stderr redirection187 # Setup stdout/stderr redirection
189 kwargs['stdout'] = subprocess.PIPE188 kwargs['stdout'] = subprocess.PIPE
190 kwargs['stderr'] = subprocess.PIPE189 kwargs['stderr'] = subprocess.PIPE
191 kwargs['start_new_session'] = True190 kwargs['start_new_session'] = True
192 # Prepare stdio supply
193 in_r, in_w = os.pipe()
194 # first let's punch the password in
195 # we need it only if the target user differs from the one that
196 # started checkbox and when changing the user (sudo) requires
197 # password
198 if target_user and self._password_provider:
199 password = self._password_provider()
200 if password:
201 os.write(in_w, password + b'\n')
202
203 def stdin_forwarder(stdin):
204 """Forward data from one pipe to the other."""
205 # use systems stdin if the stdin pipe wasn't provided
206 stdin = stdin or sys.stdin
207 try:
208 while is_alive:
209 if stdin in select.select([stdin], [], [], 0)[0]:
210 buf = stdin.readline()
211 if buf == '':
212 os.close(in_w)
213 break
214 os.write(in_w, buf.encode(stdin.encoding))
215 else:
216 time.sleep(0.1)
217 except BrokenPipeError:
218 pass
219 forwarder_thread = threading.Thread(
220 target=stdin_forwarder, args=(stdin,))
221 forwarder_thread.start()
222 kwargs['stdin'] = in_r
223
224 # Start the process191 # Start the process
225 proc = extcmd_popen._popen(*args, **kwargs)192 proc = extcmd_popen._popen(*args, **kwargs)
226 self._running_jobs_pid = proc.pid193 self._running_jobs_pid = proc.pid
@@ -238,7 +205,10 @@ class UnifiedRunner(IJobRunner):
238 try:205 try:
239 while True:206 while True:
240 try:207 try:
241 proc.wait()208 pass_bytes=None
209 if target_user and self._password_provider:
210 pass_bytes = self._password_provider() + b'\n'
211 proc.communicate(input=pass_bytes)
242 break212 break
243 except KeyboardInterrupt:213 except KeyboardInterrupt:
244 # On interrupt send a signal to the process214 # On interrupt send a signal to the process
@@ -255,9 +225,6 @@ class UnifiedRunner(IJobRunner):
255 # Tell the queue worker to shut down225 # Tell the queue worker to shut down
256 extcmd_popen._queue.put(None)226 extcmd_popen._queue.put(None)
257 queue_worker.join()227 queue_worker.join()
258 os.close(in_r)
259 is_alive = False
260 forwarder_thread.join()
261 # Notify that the process has finished228 # Notify that the process has finished
262 extcmd_popen._delegate.on_end(proc.returncode)229 extcmd_popen._delegate.on_end(proc.returncode)
263 return proc.returncode230 return proc.returncode

Subscribers

People subscribed via source and target branches