diff --git a/src/run.c b/src/run.c index 402ae6c2cb..d79cb64530 100644 --- a/src/run.c +++ b/src/run.c @@ -37,11 +37,14 @@ enum OPTION_NO_SUBREAPER, OPTION_NO_NEW_KEYRING, OPTION_PRESERVE_FDS, - OPTION_NO_PIVOT + OPTION_NO_PIVOT, + OPTION_KEEP, }; static const char *bundle = NULL; +static bool keep = false; + static libcrun_context_t crun_context; static struct argp_option options[] @@ -52,6 +55,7 @@ static struct argp_option options[] "path to a socket that will receive the ptmx end of the tty", 0 }, { "preserve-fds", OPTION_PRESERVE_FDS, "N", 0, "pass additional FDs to the container", 0 }, { "pid-file", OPTION_PID_FILE, "FILE", 0, "where to write the PID of the container", 0 }, + { "keep", OPTION_KEEP, 0, 0, "do not delete the container after it exits", 0 }, { "no-subreaper", OPTION_NO_SUBREAPER, 0, 0, "do not create a subreaper process", 0 }, { "no-new-keyring", OPTION_NO_NEW_KEYRING, 0, 0, "keep the same session key", 0 }, { "no-pivot", OPTION_NO_PIVOT, 0, 0, "do not use pivot_root", 0 }, @@ -80,6 +84,10 @@ parse_opt (int key, char *arg, struct argp_state *state) bundle = crun_context.bundle = argp_mandatory_argument (arg, state); break; + case OPTION_KEEP: + keep = true; + break; + case OPTION_CONSOLE_SOCKET: crun_context.console_socket = argp_mandatory_argument (arg, state); break; @@ -175,5 +183,5 @@ crun_command_run (struct crun_global_arguments *global_args, int argc, char **ar crun_context.preserve_fds += crun_context.listen_fds; } - return libcrun_container_run (&crun_context, container, 0, err); + return libcrun_container_run (&crun_context, container, keep ? LIBCRUN_RUN_OPTIONS_KEEP : 0, err); } diff --git a/tests/test_start.py b/tests/test_start.py index a9d8ae68fa..da74820c26 100755 --- a/tests/test_start.py +++ b/tests/test_start.py @@ -503,6 +503,43 @@ def test_ioprio(): run_crun_command(["delete", "-f", cid]) return 0 +def test_run_keep(): + conf = base_config() + conf['process']['args'] = ['/init', 'cat', '/dev/null'] + add_all_namespaces(conf) + try: + out, cid = run_and_get_output(conf, command='run') + except: + sys.stderr.write("failed to create container\n") + return -1 + + # without --keep, we must be able to recreate the container with the same id + try: + out, cid = run_and_get_output(conf, command='run', keep=True, id_container=cid) + except: + sys.stderr.write("failed to create container\n") + return -1 + + # now it must fail + try: + try: + out, cid = run_and_get_output(conf, command='run', keep=True, id_container=cid) + sys.stderr.write("run --keep succeeded twice\n") + return -1 + except: + # expected + pass + + try: + s = run_crun_command(["state", cid]) + except: + sys.stderr.write("crun state failed on --keep container\n") + return -1 + finally: + run_crun_command(["delete", "-f", cid]) + + return 0 + all_tests = { "start" : test_start, "start-override-config" : test_start_override_config, @@ -524,6 +561,7 @@ def test_ioprio(): "uts-sysctl": test_uts_sysctl, "unknown-sysctl": test_unknown_sysctl, "ioprio": test_ioprio, + "run-keep": test_run_keep, } if __name__ == "__main__": diff --git a/tests/tests_utils.py b/tests/tests_utils.py index eba61561d6..7c79c924d5 100755 --- a/tests/tests_utils.py +++ b/tests/tests_utils.py @@ -208,6 +208,7 @@ def get_crun_path(): return os.getenv("OCI_RUNTIME") or os.path.join(cwd, "crun") def run_and_get_output(config, detach=False, preserve_fds=None, pid_file=None, + keep=False, command='run', env=None, use_popen=False, hide_stderr=False, cgroup_manager='cgroupfs', all_dev_null=False, id_container=None, relative_config_path="config.json", chown_rootfs_to=None, callback_prepare_rootfs=None): @@ -266,12 +267,13 @@ def run_and_get_output(config, detach=False, preserve_fds=None, pid_file=None, callback_prepare_rootfs(rootfs) detach_arg = ['--detach'] if detach else [] + keep_arg = ['--keep'] if keep else [] preserve_fds_arg = ['--preserve-fds', str(preserve_fds)] if preserve_fds else [] pid_file_arg = ['--pid-file', pid_file] if pid_file else [] relative_config_path = ['--config', relative_config_path] if relative_config_path else [] root = get_tests_root_status() - args = [crun, "--cgroup-manager", cgroup_manager, "--root", root, command] + relative_config_path + preserve_fds_arg + detach_arg + pid_file_arg + [id_container] + args = [crun, "--cgroup-manager", cgroup_manager, "--root", root, command] + relative_config_path + preserve_fds_arg + detach_arg + keep_arg + pid_file_arg + [id_container] stderr = subprocess.STDOUT if hide_stderr: