From 97d494b06731f7e39d113e0696af1066bc159363 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Tue, 24 Oct 2017 10:49:43 -0400 Subject: [PATCH] Multiple framework fixes Signed-off-by: Jonathan Rajotte --- lttng_ivc/config.yaml | 30 ++++- lttng_ivc/settings.py | 9 +- .../test_ust_so_name_vs_tools.py | 4 +- lttng_ivc/utils/ProjectFactory.py | 2 +- lttng_ivc/utils/project.py | 42 +++++-- lttng_ivc/utils/runtime.py | 118 +++++++++++++----- 6 files changed, 160 insertions(+), 45 deletions(-) diff --git a/lttng_ivc/config.yaml b/lttng_ivc/config.yaml index bc0281b..a70a156 100644 --- a/lttng_ivc/config.yaml +++ b/lttng_ivc/config.yaml @@ -2,23 +2,51 @@ lttng-tools: - marker: lttng-tools-2.7 url: https://github.com/lttng/lttng-tools ref: stable-2.7 + precook_deps: [lttng-ust-2.7] - marker: lttng-tools-2.8 url: https://github.com/lttng/lttng-tools ref: stable-2.8 + precook_deps: [lttng-ust-2.8] + - marker: lttng-tools-2.9 + url: https://github.com/lttng/lttng-tools + ref: stable-2.9 + precook_deps: [lttng-ust-2.9] + - marker: lttng-tools-2.10 + url: https://github.com/lttng/lttng-tools + ref: stable-2.10 + precook_deps: [lttng-ust-2.10] lttng-ust: - marker: lttng-ust-2.7 url: https://github.com/lttng/lttng-ust ref: stable-2.7 + - marker: lttng-ust-2.8 + url: https://github.com/lttng/lttng-ust + ref: stable-2.8 + - marker: lttng-ust-2.9 + url: https://github.com/lttng/lttng-ust + ref: stable-2.9 - marker: lttng-ust-2.10 url: https://github.com/lttng/lttng-ust - ref: stable-2.7 + ref: stable-2.10 lttng-modules: - marker: lttng-modules-2.7 url: https://github.com/lttng/lttng-modules ref: stable-2.7 + - marker: lttng-modules-2.8 + url: https://github.com/lttng/lttng-modules + ref: stable-2.8 + - marker: lttng-modules-2.9 + url: https://github.com/lttng/lttng-modules + ref: stable-2.9 + - marker: lttng-modules-2.10 + url: https://github.com/lttng/lttng-modules + ref: stable-2.10 babeltrace: + - marker: babeltrace-1.5 + url: https://github.com/efficios/babeltrace + ref: stable-1.5 - marker: babeltrace-master url: https://github.com/efficios/babeltrace ref: master diff --git a/lttng_ivc/settings.py b/lttng_ivc/settings.py index 3a67f5a..a2a1b2f 100644 --- a/lttng_ivc/settings.py +++ b/lttng_ivc/settings.py @@ -1,10 +1,17 @@ # All tests are run if empty import os -test_only = {"lttng-ust-2.7"} +test_only = {} configuration_file = os.path.dirname(os.path.abspath(__file__)) + "/config.yaml" run_configuration_file = os.path.dirname(os.path.abspath(__file__)) + "/run_configuration.yaml" projects_cache_folder = os.path.dirname(os.path.abspath(__file__)) + "/runtime/projects_cache" git_remote_folder = os.path.dirname(os.path.abspath(__file__)) + "/runtime/git_remote" +app_folder = os.path.dirname(os.path.abspath(__file__)) + "/runtime/git_remote" +apps_folder = os.path.dirname(os.path.abspath(__file__)) + "/apps" +apps_gen_events_folder = os.path.join(apps_folder, "gen_ust_events") + +tmp_object_prefix = "lttng-ivc-" + +default_babeltrace = "babeltrace-1.5" diff --git a/lttng_ivc/tests/ust_soname_vs_tools/test_ust_so_name_vs_tools.py b/lttng_ivc/tests/ust_soname_vs_tools/test_ust_so_name_vs_tools.py index fbb2a13..5e06fd6 100644 --- a/lttng_ivc/tests/ust_soname_vs_tools/test_ust_so_name_vs_tools.py +++ b/lttng_ivc/tests/ust_soname_vs_tools/test_ust_so_name_vs_tools.py @@ -74,8 +74,8 @@ else: @pytest.mark.parametrize("ust_label,tools_label,base_tools_ust_dep,should_pass", runtime_matrix_label) def test_soname_configure(tmpdir, ust_label, tools_label, base_tools_ust_dep, should_pass): - ust = ProjectFactory.get(ust_label, str(tmpdir.mkdir("lttng-ust"))) - tools = ProjectFactory.get(tools_label, str(tmpdir.mkdir("lttng-tools"))) + ust = ProjectFactory.get_fresh(ust_label, str(tmpdir.mkdir("lttng-ust"))) + tools = ProjectFactory.get_fresh(tools_label, str(tmpdir.mkdir("lttng-tools"))) ust.autobuild() diff --git a/lttng_ivc/utils/ProjectFactory.py b/lttng_ivc/utils/ProjectFactory.py index e50e290..5daba55 100644 --- a/lttng_ivc/utils/ProjectFactory.py +++ b/lttng_ivc/utils/ProjectFactory.py @@ -37,7 +37,7 @@ def get_fresh(label, tmpdir): def _validate_pickle(pickle, label): - _logger.warn("Checking validate for {} {}".format(pickle, + _logger.debug("Checking validate for {} {}".format(pickle, label)) if pickle.label != label: _logger.warn("Label {} and {} are not the same".format(pickle.label, diff --git a/lttng_ivc/utils/project.py b/lttng_ivc/utils/project.py index 50df687..7e99571 100644 --- a/lttng_ivc/utils/project.py +++ b/lttng_ivc/utils/project.py @@ -19,6 +19,7 @@ class Project(object): if ccache is not None: self.custom_configure_flags.append("CC={} gcc".format(ccache)) self.custom_configure_flags.append("CXX={} g++".format(ccache)) + self.custom_configure_flags.append("CFLAGS=-g -O0".format(ccache)) """ A collection of Project dependencies """ self.dependencies = {} @@ -34,6 +35,10 @@ class Project(object): self.source_path = os.path.join(tmpdir, "source") self.installation_path = os.path.join(tmpdir, "install") + if os.path.isdir(self.basedir): + # Perform cleanup since it should not happen + shutil.rmtree(self.basedir) + os.makedirs(self.log_path) os.makedirs(self.source_path) os.makedirs(self.installation_path) @@ -130,12 +135,26 @@ class Project(object): if self.isConfigured ^ self.isBuilt ^ self.isInstalled: raise Exception("Project steps where manually triggered. Can't autobuild") - _logger.debug("% Autobuild configure", self.label) - self.configure() - _logger.debug("% Autobuild build", self.label) - self.build() - _logger.debug("% Autobuild install", self.label) - self.install() + _logger.debug("{} Autobuild configure".format(self.label)) + try: + self.configure() + except subprocess.CalledProcessError as e: + _logger.error("{} Configure failed. See {} for more details.".format(self.label, self.log_path)) + raise e + + _logger.debug("{} Autobuild build".format(self.label)) + try: + self.build() + except subprocess.CalledProcessError as e: + _logger.error("{} Build failed. See {} for more details.".format(self.label, self.log_path)) + raise e + + _logger.debug("{} Autobuild install".format(self.label)) + try: + self.install() + except subprocess.CalledProcessError as e: + _logger.error("{} Install failed. See {} for more details.".format(self.label, self.log_path)) + raise e def checkout(self): if self._immutable: @@ -209,13 +228,13 @@ class Project(object): os.chdir(self.source_path) args = ['make'] env = self.get_env() - env['CFLAGS'] = '-g -O0' # Number of usable cpu # https://docs.python.org/3/library/os.html#os.cpu_count num_cpu = str(len(os.sched_getaffinity(0))) args.append('-j') args.append(num_cpu) + args.append('V=1') # TODO: log output and add INFO log point with args with open(out, 'w') as stdout, open(err, 'w') as stderr: @@ -233,8 +252,8 @@ class Project(object): if self._immutable: raise Exception("Object is immutable. Illegal install") - out = os.path.join(self.log_path, "build.out") - err = os.path.join(self.log_path, "build.err") + out = os.path.join(self.log_path, "install.out") + err = os.path.join(self.log_path, "install.err") os.chdir(self.source_path) args = ['make', 'install'] @@ -255,6 +274,11 @@ class Project(object): class Lttng_modules(Project): + def __init__(self, label, git_path, sha1, tmpdir): + super(Lttng_modules, self).__init__(label=label, git_path=git_path, + sha1=sha1, tmpdir=tmpdir) + self.add_special_env_variable("MODPROBE_OPTIONS","-b {}".format(self.installation_path)) + def bootstrap(self): pass diff --git a/lttng_ivc/utils/runtime.py b/lttng_ivc/utils/runtime.py index 1bd8cbf..c2d0b83 100644 --- a/lttng_ivc/utils/runtime.py +++ b/lttng_ivc/utils/runtime.py @@ -1,12 +1,29 @@ import os +import sys import shlex import subprocess import uuid import logging +import shutil +import contextlib +import pprint +import traceback +from tempfile import TemporaryDirectory + +import lttng_ivc.settings as Settings _logger = logging.getLogger("Runtime") +@contextlib.contextmanager +def get_runtime(runtime_dir): + runtime = Runtime(runtime_dir) + try: + yield runtime + finally: + runtime.close() + + class Runtime(object): def __init__(self, runtime_dir): """ @@ -20,16 +37,32 @@ class Runtime(object): self.__runtime_log = os.path.join(runtime_dir, "log") self.__runtime_log_sub = os.path.join(self.__runtime_log, "subprocess") + """ + Path of the copy of lttng_home folder after Runtime.close() is issued. This is + to be used for post runtime analysis and mostly debugging on error. + """ + self.__post_runtime_lttng_home_path = os.path.join(runtime_dir, + "lttng_home") + self._runtime_log_aggregation = os.path.join(self.__runtime_log, "runtime.log") self._run_command_count = 0 - self.lttng_home = os.path.join(runtime_dir, "lttng_home") + self.special_env_variables = {"LTTNG_UST_DEBUG": "1", + #"LTTNG_APP_SOCKET_TIMEOUT": "-1", + #"LTTNG_UST_REGISTER_TIMEOUT": "-1", + "LTTNG_NETWORK_SOCKET_TIMEOUT": "-1"} - # TODO move exist_ok to false !!!! ONLY for testing - os.makedirs(self.__runtime_log, exist_ok=True) - os.makedirs(self.__runtime_log_sub, exist_ok=True) - os.makedirs(self.lttng_home, exist_ok=True) + # Keep a reference on the object to keep it alive. It will close/clean on + # exit. + self.__lttng_home_dir = TemporaryDirectory(prefix=Settings.tmp_object_prefix) + self.lttng_home = self.__lttng_home_dir.name + + if len(self.lttng_home) > 88: + raise Exception("TemporaryDirectory for lttng_home is to long. Use a short TMPDIR") + + os.makedirs(self.__runtime_log) + os.makedirs(self.__runtime_log_sub) def add_project(self, project): self.__projects.append(project) @@ -44,6 +77,7 @@ class Runtime(object): stdout, stderr = self.__stdout_stderr[subprocess_uuid] stdout.close() stderr.close() + return process def subprocess_kill(self, subprocess_uuid): process = self.__subprocess[subprocess_uuid] @@ -52,6 +86,7 @@ class Runtime(object): stdout, stderr = self.__stdout_stderr[subprocess_uuid] stdout.close() stderr.close() + return process def get_subprocess_stdout_path(self, subprocess_uuid): stdout, stderr = self.__stdout_stderr[subprocess_uuid] @@ -61,22 +96,31 @@ class Runtime(object): stdout, stderr = self.__stdout_stderr[subprocess_uuid] return stderr.name - def spawn_subprocess(self, command_line): + def spawn_subprocess(self, command_line, cwd=None): args = shlex.split(command_line) env = self.get_env() + if not os.path.isdir(self.lttng_home): + raise Exception("lttng home does not exist") + tmp_id = uuid.uuid1() out_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".out") err_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".err") - stdout = open(out_path, "w") - stderr = open(err_path, "w") + + stdout = open(out_path, 'w') + stderr = open(err_path, 'w') + + env_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".env") + with open(env_path, 'w') as env_out: + pprint.pprint(env, stream=env_out) p = subprocess.Popen(args, stdout=stdout, stderr=stderr, env=env) self.__subprocess[tmp_id] = p self.__stdout_stderr[tmp_id] = (stdout, stderr) _logger.debug("Spawned sub pid: {} args: {} stdout: {} stderr{}".format(p.pid, p.args, out_path, err_path)) + return tmp_id - def run(self, command_line): + def run(self, command_line, cwd=None, check_return=True): """ Run the command and return a tuple of a (CompletedProcess, stdout_path, stderr_path). The subprocess is already executed and returned. The @@ -88,35 +132,38 @@ class Runtime(object): tmp_id = self._run_command_count self._run_command_count += 1 + cmd_map = os.path.join(self.__runtime_log, "cmd.map") + with open(cmd_map, 'a') as out: + out.write("{}: {}\n".format(tmp_id, args)) + out_path = os.path.join(self.__runtime_log, str(tmp_id) + ".out") err_path = os.path.join(self.__runtime_log, str(tmp_id) + ".err") stdout = open(out_path, "w") stderr = open(err_path, "w") - stdout.write("Output for command #{} {}\n".format(tmp_id, command_line)) - stdout.write("Start >>>>>>>>>>>>>>>>\n") - stdout.flush() - - stderr.write("Output for command #{} {}\n".format(tmp_id, command_line)) - stderr.write("Start >>>>>>>>>>>>>>>>\n") - stderr.flush() + env_path = os.path.join(self.__runtime_log, str(tmp_id) + ".env") + with open(env_path, 'w') as env_out: + pprint.pprint(env, stream=env_out) - cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env) + cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env, cwd=cwd) _logger.debug("Command #{} args: {} stdout: {} stderr{}".format(tmp_id, cp.args, out_path, err_path)) - stdout.write("End <<<<<<<<<<<<<<<<\n") - stdout.close() - - stderr.write("End <<<<<<<<<<<<<<<<\n") - stderr.close() - # Add to the global log file. This can help a little. Leave the other # file available for per-run analysis with open(self._runtime_log_aggregation, "a") as log: with open(out_path, "r") as out: + log.write("Output for command #{} {}\n".format(tmp_id, command_line)) + log.write("Start >>>>>>>>>>>>>>>>\n") log.write(out.read()) + log.write("End <<<<<<<<<<<<<<<<\n") with open(err_path, "r") as out: + log.write("Error for command #{} {}\n".format(tmp_id, command_line)) + log.write("Start >>>>>>>>>>>>>>>>\n") log.write(out.read()) + log.write("End <<<<<<<<<<<<<<<<\n") + + if check_return: + cp.check_returncode() return (cp, out_path, err_path) @@ -151,7 +198,7 @@ class Runtime(object): env_fetch = {"CPPFLAGS": (self.get_cppflags(), " "), "LDFLAGS": (self.get_ldflags(), " "), - "LD_LIRABRY_PATH": (self.get_ld_library_path(), ":"), + "LD_LIBRARY_PATH": (self.get_ld_library_path(), ":"), "PATH": (self.get_bin_path(), ":"), } for key, (value, delimiter) in env_fetch.items(): @@ -160,6 +207,15 @@ class Runtime(object): tmp_var = env[key] env[key] = delimiter.join([value, tmp_var]) + for var, value in self.special_env_variables.items(): + if var in env: + # Raise for now since no special cases is known + _logger.warning("% Special var % is already defined", + self.label, var) + raise Exception("Multiple definition of a special environment variable") + else: + env[var] = value + for project in self.__projects: for var, value in project.special_env_variables.items(): if var in env: @@ -175,13 +231,13 @@ class Runtime(object): for key, subp in self.__subprocess.items(): subp.terminate() for key, subp in self.__subprocess.items(): - try: - # TODO move timeout to settings - subp.wait(timeout=60) - except subprocess.TimeoutExpired as e: - # Force a little bit - subp.kill() - subp.wait() + # TODO move timeout to settings + subp.wait(timeout=60) for key, (stdout, stderr) in self.__stdout_stderr.items(): stdout.close() stderr.close() + + # Copy the lttng_home used at runtime using hardlink to prevent useless + # data duplication + shutil.copytree(self.lttng_home, self.__post_runtime_lttng_home_path, copy_function=os.link) + -- 2.34.1