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

Proposed by Sylvain Pineau
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 983da89c370c3deb4f54b7dd64930c6e771bd9b1
Merged at revision: b09afbb6132f73ff0c95ebee521d1970c8d57b9a
Proposed branch: ~sylvain-pineau/checkbox-ng:fix-1841874
Merge into: checkbox-ng:master
Diff against target: 148 lines (+72/-13)
1 file modified
plainbox/impl/execution.py (+72/-13)
Reviewer Review Type Date Requested Status
Maciej Kisielewski (community) Approve
Review via email: mp+373195@code.launchpad.net

Description of the change

The old runner/ctrl code did prepare a differential env for jobs running as root to only carry on some specific user var bit not all.

The unified runner did not have this distinction. This patch brings back the get_differential_execution_environment function.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

tested with the stress auto test plan with both power30 and reboot30 selected.

Revision history for this message
Maciej Kisielewski (kissiel) wrote :

Hmmm. Now I finally understand what this was for :D

Thanks for fixing it!

review: Approve

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 f73aec2..410df68 100644
--- a/plainbox/impl/execution.py
+++ b/plainbox/impl/execution.py
@@ -278,12 +278,13 @@ class UnifiedRunner(IJobRunner):
278 {"ID": job.id, "CMD": cmd,278 {"ID": job.id, "CMD": cmd,
279 "ENV": env})279 "ENV": env})
280 if 'preserve-cwd' in job.get_flag_set() or os.getenv("SNAP"):280 if 'preserve-cwd' in job.get_flag_set() or os.getenv("SNAP"):
281 return_code = call(extcmd_popen, cmd, stdin=subprocess.PIPE,281 return_code = call(
282 env=env)282 extcmd_popen, cmd, stdin=subprocess.PIPE, env=env)
283 else:283 else:
284 with self.temporary_cwd(job, config) as cwd_dir:284 with self.temporary_cwd(job, config) as cwd_dir:
285 return_code = call(extcmd_popen, cmd,285 return_code = call(
286 stdin=subprocess.PIPE, env=env, cwd=cwd_dir)286 extcmd_popen, cmd, stdin=subprocess.PIPE, env=env,
287 cwd=cwd_dir)
287 if 'noreturn' in job.get_flag_set():288 if 'noreturn' in job.get_flag_set():
288 import signal289 import signal
289 signal.pause()290 signal.pause()
@@ -365,10 +366,11 @@ class UnifiedRunner(IJobRunner):
365 if leftovers:366 if leftovers:
366 logger.warning(367 logger.warning(
367 _("Job {0} created leftover filesystem artefacts"368 _("Job {0} created leftover filesystem artefacts"
368 " in its working directory").format(job.id))369 " in its working directory").format(job.id))
369 for item in leftovers:370 for item in leftovers:
370 logger.warning(_("Leftover file/directory: %r"),371 logger.warning(_(
371 os.path.relpath(item, cwd_dir))372 "Leftover file/directory: %r"),
373 os.path.relpath(item, cwd_dir))
372 logger.warning(374 logger.warning(
373 _("Please store desired files in $PLAINBOX_SESSION_SHARE"375 _("Please store desired files in $PLAINBOX_SESSION_SHARE"
374 "and use regular temporary files for everything else"))376 "and use regular temporary files for everything else"))
@@ -385,8 +387,8 @@ class UnifiedRunner(IJobRunner):
385 in_r, in_w = os.pipe()387 in_r, in_w = os.pipe()
386 os.write(in_w, self._password_provider() + b'\n')388 os.write(in_w, self._password_provider() + b'\n')
387 cmd = ['sudo', '--prompt', '', '--reset-timestamp', '--stdin',389 cmd = ['sudo', '--prompt', '', '--reset-timestamp', '--stdin',
388 '--user', 'root', 'kill', '-s', str(signal),390 '--user', 'root', 'kill', '-s', str(signal),
389 '-{}'.format(self._running_jobs_pid)]391 '-{}'.format(self._running_jobs_pid)]
390 try:392 try:
391 subprocess.check_call(cmd, stdin=in_r)393 subprocess.check_call(cmd, stdin=in_r)
392 except subprocess.CalledProcessError:394 except subprocess.CalledProcessError:
@@ -418,14 +420,13 @@ class FakeJobRunner(UnifiedRunner):
418 builder.return_code = 0420 builder.return_code = 0
419 return builder.get_result()421 return builder.get_result()
420422
423
421def get_execution_environment(job, config, session_dir, nest_dir):424def get_execution_environment(job, config, session_dir, nest_dir):
422 """425 """
423 Get the environment required to execute the specified job:426 Get the environment required to execute the specified job:
424427
425 :param job:428 :param job:
426 job definition with the command and environment definitions429 job definition with the command and environment definitions
427 :param job_state:
428 The JobState associated to the job to execute.
429 :param config:430 :param config:
430 A PlainBoxConfig instance which can be used to load missing environment431 A PlainBoxConfig instance which can be used to load missing environment
431 definitions that apply to all jobs. It is used to provide values for432 definitions that apply to all jobs. It is used to provide values for
@@ -477,6 +478,7 @@ def get_execution_environment(job, config, session_dir, nest_dir):
477 [nest_dir] + env.get("PATH", "").split(os.pathsep))478 [nest_dir] + env.get("PATH", "").split(os.pathsep))
478 # Add per-session shared state directory479 # Add per-session shared state directory
479 env['PLAINBOX_SESSION_SHARE'] = os.path.join(session_dir, "CHECKBOX_DATA")480 env['PLAINBOX_SESSION_SHARE'] = os.path.join(session_dir, "CHECKBOX_DATA")
481
480 def set_if_not_none(envvar, source):482 def set_if_not_none(envvar, source):
481 """Update env if the source variable is not None"""483 """Update env if the source variable is not None"""
482 if source is not None:484 if source is not None:
@@ -497,6 +499,59 @@ def get_execution_environment(job, config, session_dir, nest_dir):
497 env[env_var] = config.environment[env_var]499 env[env_var] = config.environment[env_var]
498 return env500 return env
499501
502
503def get_differential_execution_environment(job, config, session_dir, nest_dir):
504 """
505 Get the environment required to execute the specified job:
506
507 :param job:
508 job definition with the command and environment definitions
509 :param config:
510 A PlainBoxConfig instance which can be used to load missing
511 environment definitions that apply to all jobs. It is used to
512 provide values for missing environment variables that are required
513 by the job (as expressed by the environ key in the job definition
514 file).
515 :param session_dir:
516 Base directory of the session this job will execute in.
517 This directory is used to co-locate some data that is unique to
518 this execution as well as data that is shared by all executions.
519 :param nest_dir:
520 A directory with a nest of symlinks to all executables required to
521 execute the specified job. This is simply passed to
522 :meth:`get_execution_environment()` directly.
523 :returns:
524 Differential environment (see below).
525
526 This implementation computes the desired environment (as it was
527 computed in the base class) and then discards all of the environment
528 variables that are identical in both sets. The exception are variables
529 that are mentioned in
530 :meth:`plainbox.impl.job.JobDefinition.get_environ_settings()` which
531 are always retained.
532 """
533 base_env = os.environ
534 target_env = get_execution_environment(job, config, session_dir, nest_dir)
535 delta_env = {
536 key: value
537 for key, value in target_env.items()
538 if key not in base_env or base_env[key] != value
539 or key in job.get_environ_settings()
540 }
541 if 'reset-locale' in job.get_flag_set():
542 delta_env['LANG'] = 'C.UTF-8'
543 delta_env['LANGUAGE'] = ''
544 delta_env['LC_ALL'] = 'C.UTF-8'
545 # Preserve the copy_vars variables + those prefixed with SNAP on Snappy
546 if (os.getenv("SNAP") or os.getenv("SNAP_APP_PATH")):
547 copy_vars = ['PYTHONHOME', 'PYTHONUSERBASE', 'LD_LIBRARY_PATH',
548 'GI_TYPELIB_PATH']
549 for key, value in base_env.items():
550 if key in copy_vars or key.startswith('SNAP'):
551 delta_env[key] = value
552 return delta_env
553
554
500def get_execution_command(job, config, session_dir,555def get_execution_command(job, config, session_dir,
501 nest_dir, target_user=None):556 nest_dir, target_user=None):
502 """Generate a command argv to run in the shell."""557 """Generate a command argv to run in the shell."""
@@ -509,9 +564,13 @@ def get_execution_command(job, config, session_dir,
509 # - gets password as the first line of stdin (--stdin)564 # - gets password as the first line of stdin (--stdin)
510 # - change the user to the target user (--user)565 # - change the user to the target user (--user)
511 cmd = ['sudo', '--prompt', '', '--reset-timestamp', '--stdin',566 cmd = ['sudo', '--prompt', '', '--reset-timestamp', '--stdin',
512 '--user', target_user]567 '--user', target_user]
513 cmd += ['env']568 cmd += ['env']
514 env = get_execution_environment(job, config, session_dir, nest_dir)569 if target_user:
570 env = get_differential_execution_environment(
571 job, config, session_dir, nest_dir)
572 else:
573 env = get_execution_environment(job, config, session_dir, nest_dir)
515 cmd += ["{key}={value}".format(key=key, value=value)574 cmd += ["{key}={value}".format(key=key, value=value)
516 for key, value in sorted(env.items())]575 for key, value in sorted(env.items())]
517 cmd += [job.shell, '-c', job.command]576 cmd += [job.shell, '-c', job.command]

Subscribers

People subscribed via source and target branches