blob: 9f06d151bc3ce843724ab47d4dae596cddfd2122 [file] [edit]
############################################################################
# Copyright (C) SchedMD LLC.
############################################################################
import pytest
import atf
import logging
@pytest.fixture(scope="module", autouse=True)
def setup():
atf.require_version((25, 11), "sbin/slurmctld")
atf.require_nodes(4)
atf.require_slurm_running()
@pytest.fixture(scope="function", autouse=True)
def get_and_down_nodes():
logging.info("Getting the necessary 3 nodes:")
nodes = atf.run_job_nodes("-N3 true", fatal=True)
logging.info("Setting ALL nodes Down:")
atf.run_command(
"scontrol update nodename=ALL state=down" " reason=test_resv_overlap",
user=atf.properties["slurm-user"],
fatal=True,
)
atf.repeat_until(
lambda: atf.run_command_output(
"sinfo --states=idle,mixed --Format=NodeList -h"
),
lambda not_down: not_down == "",
fatal=True,
)
yield nodes
atf.run_command(
"scontrol delete reservationname=resv1",
user=atf.properties["slurm-user"],
quiet=True,
)
atf.run_command(
"scontrol delete reservationname=resv2",
user=atf.properties["slurm-user"],
quiet=True,
)
atf.run_command(
"scontrol update nodename=ALL state=resume",
user=atf.properties["slurm-user"],
quiet=True,
)
@pytest.mark.parametrize("resv_flag", ["", "HOURLY", "DAILY", "WEEKLY"])
def test_creation_no_overlap_maint(request, get_and_down_nodes, resv_flag):
"""Verify that new reservation creation does not
allocate nodes from MAINT reservations"""
nodes = get_and_down_nodes
logging.info(f"Resuming nodes {nodes[0]} and {nodes[1]}:")
atf.run_command(
f"scontrol update" f" nodename={nodes[0]},{nodes[1]}" f" state=resume",
user=atf.properties["slurm-user"],
fatal=True,
)
atf.repeat_until(
lambda: atf.get_node_parameter(nodes[0], "state"),
lambda state: state == ["IDLE"],
fatal=True,
)
atf.repeat_until(
lambda: atf.get_node_parameter(nodes[1], "state"),
lambda state: state == ["IDLE"],
fatal=True,
)
maint_start = "NOW+1day" if resv_flag else "NOW"
logging.info(
f"Creating MAINT reservation resv1 on"
f" node {nodes[0]} (StartTime={maint_start}):"
)
rc = atf.run_command(
f"scontrol create reservation"
f" ReservationName=resv1"
f" StartTime={maint_start}"
f" duration=7-00:00:00 user=root"
f" nodes={nodes[0]} flags=MAINT",
user=atf.properties["slurm-user"],
)
assert rc["exit_code"] == 0, "MAINT reservation resv1 should be created"
flags_str = f"flags={resv_flag}" if resv_flag else ""
logging.info(f"Creating resv2 with nodecnt=1" f" ({resv_flag or 'normal'}):")
rc = atf.run_command(
f"scontrol create reservation"
f" ReservationName=resv2 StartTime=NOW"
f" nodecnt=1 duration=00:15:00"
f" user={atf.properties['test-user']}"
f" {flags_str}",
user=atf.properties["slurm-user"],
)
assert (
rc["exit_code"] == 0
), f"resv2 should be created since {nodes[1]} is available"
logging.info("Verifying resv2 picked the non-MAINT node:")
assert atf.get_reservation_parameter("resv2", "Nodes") == nodes[1], (
f"resv2 should use non-MAINT node {nodes[1]}," f" not MAINT node {nodes[0]}"
)
logging.info("Verifying resv1 still has its MAINT node:")
assert (
atf.get_reservation_parameter("resv1", "Nodes") == nodes[0]
), f"resv1 should still use MAINT node {nodes[0]}"
@pytest.mark.parametrize("resv_flag", ["", "HOURLY", "DAILY", "WEEKLY"])
def test_creation_fails_when_only_maint_nodes(request, get_and_down_nodes, resv_flag):
"""Verify that new reservation creation fails if only
MAINT nodes are available"""
nodes = get_and_down_nodes
logging.info(f"Resuming only node {nodes[0]}:")
atf.run_command(
f"scontrol update nodename={nodes[0]}" f" state=resume",
user=atf.properties["slurm-user"],
fatal=True,
)
atf.repeat_until(
lambda: atf.get_node_parameter(nodes[0], "state"),
lambda state: state == ["IDLE"],
fatal=True,
)
maint_start = "NOW+1day" if resv_flag else "NOW"
logging.info(
f"Creating MAINT reservation resv1 on"
f" node {nodes[0]} (StartTime={maint_start}):"
)
rc = atf.run_command(
f"scontrol create reservation"
f" ReservationName=resv1"
f" StartTime={maint_start}"
f" duration=7-00:00:00 user=root"
f" nodes={nodes[0]} flags=MAINT",
user=atf.properties["slurm-user"],
)
assert rc["exit_code"] == 0, "MAINT reservation resv1 should be created"
flags_str = f"flags={resv_flag}" if resv_flag else ""
logging.info(
f"Attempting to create resv2 with nodecnt=1"
f" ({resv_flag or 'normal'}) when only"
f" MAINT nodes are available:"
)
rc = atf.run_command(
f"scontrol create reservation"
f" ReservationName=resv2 StartTime=NOW"
f" nodecnt=1 duration=00:15:00"
f" user={atf.properties['test-user']}"
f" {flags_str}",
user=atf.properties["slurm-user"],
xfail=True,
)
assert rc["exit_code"] != 0, (
f"resv2 should NOT be created because the only"
f" available node {nodes[0]} is in a MAINT"
f" reservation"
)
logging.info("Verifying only the MAINT reservation exists:")
assert len(atf.get_reservations()) == 1, "Only resv1 (MAINT) should exist"