From b7f8cef2c725a0de556777a521d387a097b4c41d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:23:20 +0000 Subject: [PATCH 1/2] Initial plan From d4eeba6812bd75fca8371cb99f347cd318a36f51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:31:33 +0000 Subject: [PATCH 2/2] Fix KeyError when PBS commands return FQDN hostnames Co-authored-by: xpillons <7349410+xpillons@users.noreply.github.com> --- pbspro/src/pbspro/scheduler.py | 8 +- pbspro/test/pbspro_test/scheduler_test.py | 164 ++++++++++++++++++++++ 2 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 pbspro/test/pbspro_test/scheduler_test.py diff --git a/pbspro/src/pbspro/scheduler.py b/pbspro/src/pbspro/scheduler.py index f25393c..cbbec77 100644 --- a/pbspro/src/pbspro/scheduler.py +++ b/pbspro/src/pbspro/scheduler.py @@ -75,13 +75,17 @@ def read_schedulers( sched_dicts = pbscmd.qmgr_parsed("list", "sched") server_dicts = pbscmd.qmgr_parsed("list", "server") - server_dicts_by_host = partition_single(server_dicts, lambda s: s["server_host"]) + # Use short hostname for server dict keys to handle both FQDN and short hostnames + server_dicts_by_host = partition_single(server_dicts, lambda s: s["server_host"].split(".")[0]) ret: Dict[str, PBSProScheduler] = {} for sched_dict in sched_dicts: hostname = sched_dict["sched_host"] - server_dict = server_dicts_by_host[hostname] + # Use short hostname for lookup to handle cases where sched_host is FQDN + # but server_host entries are short hostnames + short_hostname = hostname.split(".")[0] + server_dict = server_dicts_by_host[short_hostname] for key, value in server_dict.items(): if key not in sched_dict: diff --git a/pbspro/test/pbspro_test/scheduler_test.py b/pbspro/test/pbspro_test/scheduler_test.py new file mode 100644 index 0000000..b3daa68 --- /dev/null +++ b/pbspro/test/pbspro_test/scheduler_test.py @@ -0,0 +1,164 @@ +import pytest +from unittest.mock import Mock + +from pbspro.scheduler import read_schedulers, PBSProScheduler + + +def test_read_schedulers_with_fqdn_hostnames(): + """Test that read_schedulers handles FQDN hostnames correctly when there's a mismatch + between scheduler host (FQDN) and server host (short name).""" + + # Mock pbscmd + pbscmd = Mock() + + # Mock scheduler dict with FQDN hostname + sched_dicts = [ + { + "name": "default", + "sched_host": "headnode.internal.cloudapp.net", # FQDN + "sched_log": "/var/spool/pbs/sched_logs", + "sched_priv": "/var/spool/pbs/sched_priv", + "state": "Idle", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + # Mock server dict with short hostname + server_dicts = [ + { + "name": "default", + "server_host": "headnode", # Short hostname + "state": "Active", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + pbscmd.qmgr_parsed.side_effect = lambda cmd, obj_type: { + ("list", "sched"): sched_dicts, + ("list", "server"): server_dicts + }[(cmd, obj_type)] + + # Mock resource definitions + resource_definitions = {} + + # This should now work with the fix + result = read_schedulers(pbscmd, resource_definitions) + + # Should return one scheduler + assert len(result) == 1 + assert "headnode" in result + assert isinstance(result["headnode"], PBSProScheduler) + + +def test_read_schedulers_with_matching_hostnames(): + """Test that read_schedulers works correctly when hostnames match.""" + + # Mock pbscmd + pbscmd = Mock() + + # Mock scheduler dict with short hostname + sched_dicts = [ + { + "name": "default", + "sched_host": "headnode", # Short hostname + "sched_log": "/var/spool/pbs/sched_logs", + "sched_priv": "/var/spool/pbs/sched_priv", + "state": "Idle", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + # Mock server dict with short hostname + server_dicts = [ + { + "name": "default", + "server_host": "headnode", # Short hostname + "state": "Active", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + pbscmd.qmgr_parsed.side_effect = lambda cmd, obj_type: { + ("list", "sched"): sched_dicts, + ("list", "server"): server_dicts + }[(cmd, obj_type)] + + # Mock resource definitions + resource_definitions = {} + + # This should work fine + result = read_schedulers(pbscmd, resource_definitions) + + # Should return one scheduler + assert len(result) == 1 + assert "headnode" in result + assert isinstance(result["headnode"], PBSProScheduler) + + +def test_read_schedulers_with_mixed_hostname_formats(): + """Test that read_schedulers handles mixed FQDN and short hostname formats.""" + + # Mock pbscmd + pbscmd = Mock() + + # Mock scheduler dicts with mixed hostname formats + sched_dicts = [ + { + "name": "default", + "sched_host": "headnode.internal.cloudapp.net", # FQDN + "sched_log": "/var/spool/pbs/sched_logs", + "sched_priv": "/var/spool/pbs/sched_priv", + "state": "Idle", + "scheduling": "True", + "pbs_version": "20.0.1" + }, + { + "name": "scheduler2", + "sched_host": "compute001", # Short hostname + "sched_log": "/var/spool/pbs/sched_logs2", + "sched_priv": "/var/spool/pbs/sched_priv2", + "state": "Idle", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + # Mock server dicts with mixed hostname formats + server_dicts = [ + { + "name": "default", + "server_host": "headnode", # Short hostname + "state": "Active", + "scheduling": "True", + "pbs_version": "20.0.1" + }, + { + "name": "scheduler2", + "server_host": "compute001.domain.com", # FQDN + "state": "Active", + "scheduling": "True", + "pbs_version": "20.0.1" + } + ] + + pbscmd.qmgr_parsed.side_effect = lambda cmd, obj_type: { + ("list", "sched"): sched_dicts, + ("list", "server"): server_dicts + }[(cmd, obj_type)] + + # Mock resource definitions + resource_definitions = {} + + # This should work with the fix + result = read_schedulers(pbscmd, resource_definitions) + + # Should return two schedulers + assert len(result) == 2 + assert "headnode" in result + assert "compute001" in result + assert isinstance(result["headnode"], PBSProScheduler) + assert isinstance(result["compute001"], PBSProScheduler) \ No newline at end of file