0ec87272cf6426ab133e264c0210ae2847f39b12
12 from tempfile
import TemporaryDirectory
14 import lttng_ivc
.settings
as Settings
15 _logger
= logging
.getLogger("Runtime")
18 @contextlib.contextmanager
19 def get_runtime(runtime_dir
):
20 runtime
= Runtime(runtime_dir
)
27 class Runtime(object):
28 def __init__(self
, runtime_dir
):
30 A dictionary of popen object eg. lttng-sessiond, relayd,
31 anything really. Key is a uuid.
33 self
.__subprocess
= {}
34 self
.__stdout
_stderr
= {}
37 self
.__runtime
_log
= os
.path
.join(runtime_dir
, "log")
38 self
.__runtime
_log
_sub
= os
.path
.join(self
.__runtime
_log
, "subprocess")
41 Path of the copy of lttng_home folder after Runtime.close() is issued. This is
42 to be used for post runtime analysis and mostly debugging on error.
44 self
.__post
_runtime
_lttng
_home
_path
= os
.path
.join(runtime_dir
,
47 self
._runtime
_log
_aggregation
= os
.path
.join(self
.__runtime
_log
, "runtime.log")
49 self
._run
_command
_count
= 0
50 self
._is
_test
_modules
_loaded
= False
52 self
.special_env_variables
= {"LTTNG_UST_DEBUG": "1",
53 "LTTNG_APP_SOCKET_TIMEOUT": "-1",
54 #"LTTNG_UST_REGISTER_TIMEOUT": "-1",
55 "LTTNG_NETWORK_SOCKET_TIMEOUT": "-1"}
57 # Keep a reference on the object to keep it alive. It will close/clean on
59 self
.__lttng
_home
_dir
= TemporaryDirectory(prefix
=Settings
.tmp_object_prefix
)
60 self
.lttng_home
= self
.__lttng
_home
_dir
.name
62 if len(self
.lttng_home
) > 88:
63 raise Exception("TemporaryDirectory for lttng_home is to long. Use a short TMPDIR")
65 os
.makedirs(self
.__runtime
_log
)
66 os
.makedirs(self
.__runtime
_log
_sub
)
68 def add_project(self
, project
):
69 self
.__projects
.append(project
)
71 def remove_project(self
, project
):
72 self
.__projects
.remove(project
)
74 def subprocess_signal(self
, subprocess_uuid
, signal
):
75 self
.__subproces
[subprocess_uuid
].send_signal(signal
)
77 def subprocess_terminate(self
, subprocess_uuid
, timeout
=60, check_return
=True):
78 process
= self
.__subprocess
[subprocess_uuid
]
82 except subprocess
.TimeoutExpired
:
84 return self
.subprocess_kill(subprocess_uuid
)
85 stdout
, stderr
= self
.__stdout
_stderr
[subprocess_uuid
]
89 if process
.returncode
!= 0:
90 raise subprocess
.CalledProcessError(process
.returncode
, process
.args
)
93 def subprocess_kill(self
, subprocess_uuid
):
94 process
= self
.__subprocess
[subprocess_uuid
]
97 stdout
, stderr
= self
.__stdout
_stderr
[subprocess_uuid
]
102 def subprocess_wait(self
, subprocess_uuid
, check_return
=True):
103 process
= self
.__subprocess
[subprocess_uuid
]
105 stdout
, stderr
= self
.__stdout
_stderr
[subprocess_uuid
]
109 if process
.returncode
!= 0:
110 raise subprocess
.CalledProcessError(process
.returncode
, process
.args
)
113 def get_subprocess_stdout_path(self
, subprocess_uuid
):
114 stdout
, stderr
= self
.__stdout
_stderr
[subprocess_uuid
]
117 def get_subprocess_stderr_path(self
, subprocess_uuid
):
118 stdout
, stderr
= self
.__stdout
_stderr
[subprocess_uuid
]
121 def spawn_subprocess(self
, command_line
, cwd
=None):
122 args
= shlex
.split(command_line
)
125 if not os
.path
.isdir(self
.lttng_home
):
126 raise Exception("lttng home does not exist")
128 tmp_id
= uuid
.uuid1()
129 out_path
= os
.path
.join(self
.__runtime
_log
_sub
, str(tmp_id
) + ".out")
130 err_path
= os
.path
.join(self
.__runtime
_log
_sub
, str(tmp_id
) + ".err")
132 stdout
= open(out_path
, 'w')
133 stderr
= open(err_path
, 'w')
135 env_path
= os
.path
.join(self
.__runtime
_log
_sub
, str(tmp_id
) + ".env")
136 with
open(env_path
, 'w') as env_out
:
137 pprint
.pprint(env
, stream
=env_out
)
139 p
= subprocess
.Popen(args
, stdout
=stdout
, stderr
=stderr
, env
=env
, cwd
=cwd
)
140 self
.__subprocess
[tmp_id
] = p
141 self
.__stdout
_stderr
[tmp_id
] = (stdout
, stderr
)
142 _logger
.debug("Spawned sub pid: {} args: {} stdout: {} stderr{}".format(p
.pid
, p
.args
, out_path
, err_path
))
145 def run(self
, command_line
, cwd
=None, check_return
=True, ld_preload
="", classpath
="", timeout
=None):
147 Run the command and return a tuple of a (CompletedProcess, stdout_path,
148 stderr_path). The subprocess is already executed and returned. The
149 callecaller is responsible for checking for errors.
151 args
= shlex
.split(command_line
)
155 env
['LD_PRELOAD'] = ld_preload
157 env
['CLASSPATH'] = classpath
160 tmp_id
= self
._run
_command
_count
161 self
._run
_command
_count
+= 1
163 cmd_map
= os
.path
.join(self
.__runtime
_log
, "cmd.map")
164 with
open(cmd_map
, 'a') as out
:
165 out
.write("{}: {}\n".format(tmp_id
, args
))
167 out_path
= os
.path
.join(self
.__runtime
_log
, str(tmp_id
) + ".out")
168 err_path
= os
.path
.join(self
.__runtime
_log
, str(tmp_id
) + ".err")
169 stdout
= open(out_path
, "w")
170 stderr
= open(err_path
, "w")
172 env_path
= os
.path
.join(self
.__runtime
_log
, str(tmp_id
) + ".env")
173 with
open(env_path
, 'w') as env_out
:
174 for key
, value
in env
.items():
175 env_out
.write('{}={}\n'.format(key
, value
))
177 cp
= subprocess
.run(args
, stdout
=stdout
, stderr
=stderr
, env
=env
,
178 cwd
=cwd
, timeout
=timeout
)
179 _logger
.debug("Command #{} args: {} stdout: {} stderr{}".format(tmp_id
, cp
.args
, out_path
, err_path
))
181 # Add to the global log file. This can help a little. Leave the other
182 # file available for per-run analysis
183 with
open(self
._runtime
_log
_aggregation
, "a") as log
:
184 with
open(out_path
, "r") as out
:
185 log
.write("Output for command #{} {}\n".format(tmp_id
, command_line
))
186 log
.write("Start >>>>>>>>>>>>>>>>\n")
187 log
.write(out
.read())
188 log
.write("End <<<<<<<<<<<<<<<<\n")
189 with
open(err_path
, "r") as out
:
190 log
.write("Error for command #{} {}\n".format(tmp_id
, command_line
))
191 log
.write("Start >>>>>>>>>>>>>>>>\n")
192 log
.write(out
.read())
193 log
.write("End <<<<<<<<<<<<<<<<\n")
196 cp
.check_returncode()
198 return (cp
, out_path
, err_path
)
200 def get_cppflags(self
):
202 for project
in self
.__projects
:
203 cppflags
.append(project
.get_cppflags())
204 return " ".join(cppflags
)
206 def get_ldflags(self
):
208 for project
in self
.__projects
:
209 ldflags
.append(project
.get_ldflags())
210 return " ".join(ldflags
)
212 def get_ld_library_path(self
):
214 for project
in self
.__projects
:
215 library_path
.append(project
.get_ld_library_path())
216 return ":".join(library_path
)
218 def get_bin_path(self
):
220 for project
in self
.__projects
:
221 path
.append(project
.get_bin_path())
222 return ":".join(path
)
225 env
= os
.environ
.copy()
227 env
["LTTNG_HOME"] = self
.lttng_home
229 env_fetch
= {"CPPFLAGS": (self
.get_cppflags(), " "),
230 "LDFLAGS": (self
.get_ldflags(), " "),
231 "LD_LIBRARY_PATH": (self
.get_ld_library_path(), ":"),
232 "PATH": (self
.get_bin_path(), ":"),
234 for key
, (value
, delimiter
) in env_fetch
.items():
238 env
[key
] = delimiter
.join([value
, tmp_var
])
240 for var
, value
in self
.special_env_variables
.items():
242 # Raise for now since no special cases is known
243 _logger
.warning("% Special var % is already defined",
245 raise Exception("Multiple definition of a special environment variable")
249 for project
in self
.__projects
:
250 for var
, value
in project
.special_env_variables
.items():
252 # Raise for now since no special cases is known
253 _logger
.warning("% Special var % is already defined",
255 raise Exception("Multiple definition of a special environment variable")
260 def load_test_module(self
):
261 # Base directory is provided by env
262 self
.run("modprobe lttng-test")
263 self
._is
_test
_modules
_loaded
= True
265 def unload_test_module(self
, check_return
=True):
266 # Base directory is provided by env
267 if self
._is
_test
_modules
_loaded
:
268 self
.run("modprobe -r lttng-test", check_return
=check_return
)
271 for key
, subp
in self
.__subprocess
.items():
272 self
.subprocess_kill(key
)
274 # Always try to remove test module but do not perform check on return
276 self
.unload_test_module(False)
278 # Copy the lttng_home used at runtime using hardlink to prevent useless
280 shutil
.copytree(self
.lttng_home
, self
.__post
_runtime
_lttng
_home
_path
, copy_function
=os
.link
)
This page took 0.047833 seconds and 4 git commands to generate.