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

Proposed by Sylvain Pineau
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 45722c5e52550aae0ef7d8b37962ef98c31fa128
Merged at revision: 9caac15aa15c9460effcfad0dfe33cc07713cf87
Proposed branch: ~sylvain-pineau/checkbox-ng:fix-1849872
Merge into: checkbox-ng:master
Diff against target: 115 lines (+25/-5)
2 files modified
plainbox/impl/execution.py (+11/-5)
plainbox/impl/session/remote_assistant.py (+14/-0)
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Approve
Jonathan Cave (community) Approve
Review via email: mp+374858@code.launchpad.net

Description of the change

Fixes linked bug by setting the DISPLAY env var when the remote slave service running as root runs a job as a normal user.

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

Tested on 2 remote systems (16.04 unity and 18.04 gnome )

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Improved version where the DISPLAY env is evaluated only when a session starts or resumes itself.
The extra_env is carried up to the unified runner to be part of the differential env when the service running as root switch to the normal user.

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

One potential improvement suggested below

Revision history for this message
Jonathan Cave (jocave) wrote :

Thanks for reducing the number of times it is likely these loops will need to be run. I think it would have been an unfair overhead on server and IoT runs to have done this for every job. So +1 for the compromise.

review: Approve
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

outlining the psutil stuff as requested

review: Needs Resubmitting
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

approving based on initial reviews. the current commit includes a dedicated method to prepare the DISPLAY env var

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/plainbox/impl/execution.py b/plainbox/impl/execution.py
2index 410df68..38c1221 100644
3--- a/plainbox/impl/execution.py
4+++ b/plainbox/impl/execution.py
5@@ -62,7 +62,8 @@ class UnifiedRunner(IJobRunner):
6 command_io_delegate=None, dry_run=False,
7 execution_ctrl_list=None, stdin=False,
8 normal_user_provider=lambda: None,
9- password_provider=sudo_password_provider.get_sudo_password):
10+ password_provider=sudo_password_provider.get_sudo_password,
11+ extra_env=None):
12 self._session_dir = session_dir
13 self._session_dir = session_dir
14 self._provider_list = provider_list
15@@ -78,6 +79,7 @@ class UnifiedRunner(IJobRunner):
16 self._password_provider = password_provider
17 self._stdin = stdin
18 self._running_jobs_pid = None
19+ self._extra_env = extra_env
20
21 def run_job(self, job, job_state, config=None, ui=None):
22 logger.info(_("Running %r"), job)
23@@ -269,7 +271,8 @@ class UnifiedRunner(IJobRunner):
24 # Get the command and the environment.
25 # of this execution controller
26 cmd = get_execution_command(
27- job, config, self._session_dir, nest_dir, target_user)
28+ job, config, self._session_dir, nest_dir, target_user,
29+ self._extra_env)
30 env = get_execution_environment(
31 job, config, self._session_dir, nest_dir)
32 # run the command
33@@ -500,7 +503,8 @@ def get_execution_environment(job, config, session_dir, nest_dir):
34 return env
35
36
37-def get_differential_execution_environment(job, config, session_dir, nest_dir):
38+def get_differential_execution_environment(job, config, session_dir, nest_dir,
39+ extra_env=None):
40 """
41 Get the environment required to execute the specified job:
42
43@@ -542,6 +546,8 @@ def get_differential_execution_environment(job, config, session_dir, nest_dir):
44 delta_env['LANG'] = 'C.UTF-8'
45 delta_env['LANGUAGE'] = ''
46 delta_env['LC_ALL'] = 'C.UTF-8'
47+ if extra_env:
48+ delta_env.update(extra_env)
49 # Preserve the copy_vars variables + those prefixed with SNAP on Snappy
50 if (os.getenv("SNAP") or os.getenv("SNAP_APP_PATH")):
51 copy_vars = ['PYTHONHOME', 'PYTHONUSERBASE', 'LD_LIBRARY_PATH',
52@@ -553,7 +559,7 @@ def get_differential_execution_environment(job, config, session_dir, nest_dir):
53
54
55 def get_execution_command(job, config, session_dir,
56- nest_dir, target_user=None):
57+ nest_dir, target_user=None, extra_env=None):
58 """Generate a command argv to run in the shell."""
59 cmd = []
60 if target_user:
61@@ -568,7 +574,7 @@ def get_execution_command(job, config, session_dir,
62 cmd += ['env']
63 if target_user:
64 env = get_differential_execution_environment(
65- job, config, session_dir, nest_dir)
66+ job, config, session_dir, nest_dir, extra_env)
67 else:
68 env = get_execution_environment(job, config, session_dir, nest_dir)
69 cmd += ["{key}={value}".format(key=key, value=value)
70diff --git a/plainbox/impl/session/remote_assistant.py b/plainbox/impl/session/remote_assistant.py
71index c016697..35a5b11 100644
72--- a/plainbox/impl/session/remote_assistant.py
73+++ b/plainbox/impl/session/remote_assistant.py
74@@ -41,6 +41,8 @@ from plainbox.abc import IJobResult
75 from checkbox_ng.config import load_configs
76 from checkbox_ng.launcher.run import SilentUI
77
78+import psutil
79+
80 _ = gettext.gettext
81
82 _logger = logging.getLogger("plainbox.session.remote_assistant")
83@@ -184,6 +186,16 @@ class RemoteSessionAssistant():
84 self._last_response = response
85 self._state = Running
86
87+ def prepare_extra_env(self):
88+ # If possible also set the DISPLAY env var
89+ # i.e when a user desktop session is running
90+ for p in psutil.pids():
91+ p_environ = psutil.Process(p).environ()
92+ p_user = psutil.Process(p).username()
93+ if ("DISPLAY" in p_environ and p_user != 'gdm'): # gdm uses :1024
94+ return {'DISPLAY': p_environ['DISPLAY']}
95+ break
96+
97 @allowed_when(Idle)
98 def start_session(self, configuration):
99 self._reset_sa()
100@@ -207,6 +219,7 @@ class RemoteSessionAssistant():
101 'normal_user_provider': lambda: self._normal_user,
102 'password_provider': pass_provider,
103 'stdin': self._pipe_to_subproc,
104+ 'extra_env': self.prepare_extra_env(),
105 }
106 self._sa.start_new_session(session_title, UnifiedRunner, runner_kwargs)
107 self._sa.update_app_blob(json.dumps(
108@@ -514,6 +527,7 @@ class RemoteSessionAssistant():
109 'normal_user_provider': lambda: self._normal_user,
110 'password_provider': pass_provider,
111 'stdin': self._pipe_to_subproc,
112+ 'extra_env': self.prepare_extra_env(),
113 }
114 meta = self._sa.resume_session(session_id, runner_kwargs=runner_kwargs)
115 app_blob = json.loads(meta.app_blob.decode("UTF-8"))

Subscribers

People subscribed via source and target branches