| ############################################################################ |
| # Copyright (C) SchedMD LLC. |
| ############################################################################ |
| import atf |
| |
| # import os |
| import pytest |
| import re |
| |
| |
| # Setup |
| @pytest.fixture(scope="module", autouse=True) |
| def setup(): |
| atf.require_auto_config( |
| "wants to create helpers.conf, helper scripts and reboot script" |
| ) |
| atf.require_config_parameter("NodeFeaturesPlugins", "node_features/helpers") |
| atf.require_nodes(1) |
| helper_script = make_helper_script() |
| feature_helpers_dict = {} |
| for i in range(2): |
| feature_helpers_dict[f"f{i+1}"] = {"Helper": helper_script} |
| atf.require_config_parameter("Feature", feature_helpers_dict, source="helpers") |
| atf.require_config_parameter("RebootProgram", f"{atf.module_tmp_path}/rebooter.sh") |
| atf.require_slurm_running() |
| |
| |
| # Creates the script called by each helper in the helpers.conf |
| def make_helper_script(): |
| # Helper variable storage location: |
| helpers_variable_file = f"{atf.module_tmp_path}/helper.vars" |
| |
| helper_script = f"{atf.module_tmp_path}/helper.sh" |
| atf.make_bash_script( |
| helper_script, |
| f""" |
| touch {helpers_variable_file} |
| if [ -n \"$1\" ]; then |
| echo $1 > {helpers_variable_file} |
| fi |
| cat {helpers_variable_file}""", |
| ) |
| |
| # Set initial active feature as f1 by storing it in the helper variable file |
| atf.run_command(f"echo f1 > {helpers_variable_file}", fatal=True, quiet=True) |
| atf.run_command( |
| f"chmod 0666 {helpers_variable_file}", user="root", fatal=True, quiet=True |
| ) |
| return helper_script |
| |
| |
| # Creates the rebooter script referenced in slurm.conf that kills and restarts the proper slurmd |
| def make_rebooter_script(node_name, out_file): |
| reboot_file = f"{atf.module_tmp_path}/rebooter.sh" |
| slurmd_path = f"{atf.properties['slurm-sbin-dir']}/slurmd -N {node_name}" |
| |
| atf.make_bash_script( |
| reboot_file, |
| f""" |
| slurmd_pid=$(ps -p $PPID -o ppid:1=) |
| slurmd_start_cmd=$(ps -p $slurmd_pid -o cmd=) |
| kill -9 $slurmd_pid |
| while [ $SECONDS -lt 10 ]; do |
| if ! ps -p $slurmd_pid; then |
| break |
| fi |
| done |
| $($slurmd_start_cmd -b) |
| while [ $SECONDS -lt 10 ]; do |
| if ps -p $(pgrep -f '{slurmd_path}'); then |
| echo 'done' > {out_file} |
| break |
| fi |
| done |
| """, |
| ) |
| |
| atf.run_command(f"chmod 0777 {reboot_file}", user="root", fatal=True, quiet=True) |
| |
| |
| @pytest.fixture(scope="module") |
| def our_node(): |
| # Determine our node name and wait until the node is up and at 'idle' state |
| node_name = list(atf.nodes.keys())[0] |
| atf.repeat_command_until( |
| f"sinfo -h -n {node_name} -o %t", |
| lambda results: re.search(r"idle", results["stdout"]), |
| ) |
| return node_name |
| |
| |
| def test_plugin_features(our_node): |
| """Verify plugin is enabled and ActiveFeatures != AvailableFeatures""" |
| |
| active_feats = atf.get_node_parameter(our_node, "active_features") |
| avail_feats = atf.get_node_parameter(our_node, "features") |
| assert ( |
| active_feats != avail_feats |
| ), "AvailableFeatures should not equal ActiveFeatures" |
| |
| |
| def test_request_adds_new_ActiveFeature(our_node): |
| """Verify job request with new ActiveFeature restarts, adds new ActiveFeature, and runs""" |
| |
| out_file = f"{atf.module_tmp_path}/file.out" |
| make_rebooter_script(our_node, out_file) |
| |
| # Submit a job with inactive available feature 'f2', should trigger reboot |
| atf.submit_job_sbatch(f"--wrap='true' -C f2 -w {our_node}", fatal=True) |
| |
| # Wait for output from rebooter script that indicates a successful reboot |
| atf.repeat_command_until( |
| f"cat {out_file}", |
| lambda results: re.search(r"done", results["stdout"]), |
| fatal=True, |
| timeout=30, |
| ) |
| |
| assert atf.repeat_until( |
| lambda: atf.get_node_parameter(our_node, "active_features"), |
| lambda f: f == ["f2"], |
| timeout=30, |
| fatal=True, |
| ), "f2 is not included in ActiveFeatures" |