blob: 88fae28e78085d34dae966771810bc39683d4453 [file] [edit]
############################################################################
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
############################################################################
import os
import re
import pytest
import atf
unknown_option = "nonexistent_option"
srun_only_option = "pty"
job_name = "t25956"
# One rejected assignment of each kind, then a read-back proving the hook
# kept running. Returning slurm.ERROR makes sbatch exit before submitting.
cli_filter_lua = f"""
function slurm_cli_setup_defaults(options, early)
return slurm.SUCCESS
end
function slurm_cli_pre_submit(options, offset)
options["{unknown_option}"] = "x"
options["{srun_only_option}"] = "x"
options["job-name"] = "{job_name}"
slurm.log_info("continued: job-name=%s", tostring(options["job-name"]))
return slurm.ERROR
end
function slurm_cli_post_submit(offset, jobid, stepid)
end
"""
def cli_filter_lua_available():
"""Return True when cli_filter_lua.so is installed in PluginDir."""
prefix = atf.properties["slurm-prefix"]
# get_config_parameter() casefolds values, which would mangle the path.
plugin_dir = next(
(
v
for k, v in atf.get_config(live=False).items()
if k.casefold() == "plugindir"
),
f"{prefix}/lib/slurm:{prefix}/lib64/slurm",
)
return any(
os.path.isfile(f"{directory}/cli_filter_lua.so")
for directory in plugin_dir.split(":")
)
@pytest.fixture(scope="module")
def slurm_conf():
"""Private slurm.conf enabling cli_filter/lua; the running cluster is untouched."""
atf.require_version(
(26, 11),
"bin/sbatch",
reason="cli_filter/lua logs rejected option assignments since 26.11",
)
if not cli_filter_lua_available():
pytest.skip("Requires the cli_filter/lua plugin")
lua_path = atf.module_tmp_path / "cli_filter.lua"
lua_path.write_text(cli_filter_lua)
contents = atf.run_command_output(
f"cat {atf.properties['slurm-config-dir']}/slurm.conf", fatal=True, quiet=True
)
contents = re.sub(r"(?im)^\s*CliFilter(Plugins|Parameters)\s*=.*$", "", contents)
conf_path = atf.module_tmp_path / "slurm.conf"
conf_path.write_text(
f"{contents}\nCliFilterPlugins=lua\n"
f"CliFilterParameters=cli_filter_lua_path={lua_path}\n"
)
return conf_path
def test_rejected_assignment_logs_and_continues(slurm_conf):
"""Ticket 25956: a rejected assignment logs the option name, the hook continues.
The hook assigns an unknown option, an option that exists only for srun,
and a valid one. sbatch must log the first two, apply the third, reach the
end of the hook, and then stop because the hook returns slurm.ERROR.
"""
result = atf.run_command(
"sbatch --wrap=true", env_vars=f"SLURM_CONF={slurm_conf}", xfail=True
)
stderr = result["stderr"]
assert result["exit_code"] != 0, "sbatch must stop when the hook returns ERROR"
assert "cli_filter plugin terminated with error" in stderr
assert f"Unable to set option '{unknown_option}'" in stderr
assert f"Unable to set option '{srun_only_option}'" in stderr
assert "Unable to set option 'job-name'" not in stderr
assert f"continued: job-name={job_name}" in stderr