diff --git a/slurmutils/editors/cgroupconfig.py b/slurmutils/editors/cgroupconfig.py
index 965d94a..f7dbbf7 100644
--- a/slurmutils/editors/cgroupconfig.py
+++ b/slurmutils/editors/cgroupconfig.py
@@ -20,10 +20,10 @@
import os
from contextlib import contextmanager
from pathlib import Path
-from typing import Union
+from typing import Optional, Union
from ..models import CgroupConfig
-from .editor import dumper, loader
+from .editor import dumper, loader, set_file_permissions
_logger = logging.getLogger("slurmutils")
@@ -40,9 +40,16 @@ def loads(content: str) -> CgroupConfig:
@dumper
-def dump(config: CgroupConfig, file: Union[str, os.PathLike]) -> None:
+def dump(
+ config: CgroupConfig,
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> None:
"""Dump `cgroup.conf` data model into cgroup.conf file."""
Path(file).write_text(dumps(config))
+ set_file_permissions(file, mode, user, group)
def dumps(config: CgroupConfig) -> str:
@@ -51,12 +58,19 @@ def dumps(config: CgroupConfig) -> str:
@contextmanager
-def edit(file: Union[str, os.PathLike]) -> CgroupConfig:
+def edit(
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> CgroupConfig:
"""Edit a cgroup.conf file.
Args:
- file: Path to cgroup.conf file to edit. If cgroup.conf does
- not exist at the specified file path, it will be created.
+ file: cgroup.conf file to edit. An empty config will be created if it does not exist.
+ mode: Access mode to apply to the cgroup.conf file. (Default: rw-r--r--)
+ user: User to set as owner of the cgroup.conf file. (Default: $USER)
+ group: Group to set as owner of the cgroup.conf file. (Default: None)
"""
if not os.path.exists(file):
_logger.warning("file %s not found. creating new empty cgroup.conf configuration", file)
@@ -65,4 +79,4 @@ def edit(file: Union[str, os.PathLike]) -> CgroupConfig:
config = load(file)
yield config
- dump(config, file)
+ dump(config, file, mode, user, group)
diff --git a/slurmutils/editors/editor.py b/slurmutils/editors/editor.py
index becde3b..a38866c 100644
--- a/slurmutils/editors/editor.py
+++ b/slurmutils/editors/editor.py
@@ -15,19 +15,42 @@
"""Base methods for Slurm workload manager configuration file editors."""
import logging
+import os
+import shutil
from functools import wraps
-from os import path
+from pathlib import Path
+from typing import Optional, Union
_logger = logging.getLogger("slurmutils")
+def set_file_permissions(
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> None:
+ """Set file permissions to configuration file.
+
+ Args:
+ file: File to apply permission settings to.
+ mode: Access mode to apply to file. (Default: rw-r--r--)
+ user: User to set as owner of file. (Default: $USER)
+ group: Group to set as owner of file. (Default: None)
+ """
+ Path(file).chmod(mode=mode)
+ if user is None:
+ user = os.getuid()
+ shutil.chown(file, user, group)
+
+
def loader(func):
"""Wrap function that loads configuration data from file."""
@wraps(func)
def wrapper(*args, **kwargs):
fin = args[0]
- if not path.exists(fin):
+ if not os.path.exists(fin):
raise FileNotFoundError(f"could not locate {fin}")
_logger.debug("reading contents of %s", fin)
@@ -42,7 +65,7 @@ def dumper(func):
@wraps(func)
def wrapper(*args, **kwargs):
fout = args[1]
- if path.exists(fout):
+ if os.path.exists(fout):
_logger.debug("overwriting current contents of %s", fout)
_logger.debug("updating contents of %s", fout)
diff --git a/slurmutils/editors/slurmconfig.py b/slurmutils/editors/slurmconfig.py
index 1f0aac3..b159e87 100644
--- a/slurmutils/editors/slurmconfig.py
+++ b/slurmutils/editors/slurmconfig.py
@@ -20,10 +20,10 @@
import os
from contextlib import contextmanager
from pathlib import Path
-from typing import Union
+from typing import Optional, Union
from ..models import SlurmConfig
-from .editor import dumper, loader
+from .editor import dumper, loader, set_file_permissions
_logger = logging.getLogger("slurmutils")
@@ -40,9 +40,16 @@ def loads(content: str) -> SlurmConfig:
@dumper
-def dump(config: SlurmConfig, file: Union[str, os.PathLike]) -> None:
+def dump(
+ config: SlurmConfig,
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> None:
"""Dump `slurm.conf` data model into slurm.conf file."""
Path(file).write_text(dumps(config))
+ set_file_permissions(file, mode, user, group)
def dumps(config: SlurmConfig) -> str:
@@ -51,12 +58,19 @@ def dumps(config: SlurmConfig) -> str:
@contextmanager
-def edit(file: Union[str, os.PathLike]) -> SlurmConfig:
+def edit(
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> SlurmConfig:
"""Edit a slurm.conf file.
Args:
- file: Path to slurm.conf file to edit. If slurm.conf does
- not exist at the specified file path, it will be created.
+ file: slurm.conf file to edit. An empty config will be created if it does not exist.
+ mode: Access mode to apply to the slurm.conf file. (Default: rw-r--r--)
+ user: User to set as owner of the slurm.conf file. (Default: $USER)
+ group: Group to set as owner of the slurm.conf file. (Default: None)
"""
if not os.path.exists(file):
_logger.warning("file %s not found. creating new empty slurm.conf configuration", file)
@@ -65,4 +79,4 @@ def edit(file: Union[str, os.PathLike]) -> SlurmConfig:
config = load(file)
yield config
- dump(config, file)
+ dump(config, file, mode, user, group)
diff --git a/slurmutils/editors/slurmdbdconfig.py b/slurmutils/editors/slurmdbdconfig.py
index 70f9a04..3229bc5 100644
--- a/slurmutils/editors/slurmdbdconfig.py
+++ b/slurmutils/editors/slurmdbdconfig.py
@@ -20,11 +20,10 @@
import os
from contextlib import contextmanager
from pathlib import Path
-from typing import Union
+from typing import Optional, Union
-from slurmutils.models import SlurmdbdConfig
-
-from .editor import dumper, loader
+from ..models import SlurmdbdConfig
+from .editor import dumper, loader, set_file_permissions
_logger = logging.getLogger("slurmutils")
@@ -41,9 +40,16 @@ def loads(content: str) -> SlurmdbdConfig:
@dumper
-def dump(config: SlurmdbdConfig, file: Union[str, os.PathLike]) -> None:
+def dump(
+ config: SlurmdbdConfig,
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> None:
"""Dump `slurmdbd.conf` data model into slurmdbd.conf file."""
Path(file).write_text(dumps(config))
+ set_file_permissions(file, mode, user, group)
def dumps(config: SlurmdbdConfig) -> str:
@@ -52,12 +58,19 @@ def dumps(config: SlurmdbdConfig) -> str:
@contextmanager
-def edit(file: Union[str, os.PathLike]) -> SlurmdbdConfig:
+def edit(
+ file: Union[str, os.PathLike],
+ mode: int = 0o644,
+ user: Optional[Union[str, int]] = None,
+ group: Optional[Union[str, int]] = None,
+) -> SlurmdbdConfig:
"""Edit a slurmdbd.conf file.
Args:
- file: Path to slurmdbd.conf file to edit. If slurmdbd.conf does
- not exist at the specified file path, it will be created.
+ file: slurmdbd.conf file to edit. An empty config will be created if it does not exist.
+ mode: Access mode to apply to the slurmdbd.conf file. (Default: rw-r--r--)
+ user: User to set as owner of the slurmdbd.conf file. (Default: $USER)
+ group: Group to set as owner of the slurmdbd.conf file. (Default: None)
"""
if not os.path.exists(file):
_logger.warning("file %s not found. creating new empty slurmdbd.conf configuration", file)
@@ -66,4 +79,4 @@ def edit(file: Union[str, os.PathLike]) -> SlurmdbdConfig:
config = load(file)
yield config
- dump(config, file)
+ dump(config, file, mode, user, group)
diff --git a/tests/unit/editors/constants.py b/tests/unit/editors/constants.py
new file mode 100644
index 0000000..2081302
--- /dev/null
+++ b/tests/unit/editors/constants.py
@@ -0,0 +1,108 @@
+# Copyright 2024 Canonical Ltd.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 3 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+
+EXAMPLE_SLURM_CONFIG = """#
+# `slurm.conf` file generated at 2024-01-30 17:18:36.171652 by slurmutils.
+#
+SlurmctldHost=juju-c9fc6f-0(10.152.28.20)
+SlurmctldHost=juju-c9fc6f-1(10.152.28.100)
+
+ClusterName=charmed-hpc
+AuthType=auth/munge
+Epilog=/usr/local/slurm/epilog
+Prolog=/usr/local/slurm/prolog
+FirstJobId=65536
+InactiveLimit=120
+JobCompType=jobcomp/filetxt
+JobCompLoc=/var/log/slurm/jobcomp
+KillWait=30
+MaxJobCount=10000
+MinJobAge=3600
+PluginDir=/usr/local/lib:/usr/local/slurm/lib
+ReturnToService=0
+SchedulerType=sched/backfill
+SlurmctldLogFile=/var/log/slurm/slurmctld.log
+SlurmdLogFile=/var/log/slurm/slurmd.log
+SlurmctldPort=7002
+SlurmdPort=7003
+SlurmdSpoolDir=/var/spool/slurmd.spool
+StateSaveLocation=/var/spool/slurm.state
+SwitchType=switch/none
+TmpFS=/tmp
+WaitTime=30
+
+#
+# Node configurations
+#
+NodeName=juju-c9fc6f-2 NodeAddr=10.152.28.48 CPUs=1 RealMemory=1000 TmpDisk=10000
+NodeName=juju-c9fc6f-3 NodeAddr=10.152.28.49 CPUs=1 RealMemory=1000 TmpDisk=10000
+NodeName=juju-c9fc6f-4 NodeAddr=10.152.28.50 CPUs=1 RealMemory=1000 TmpDisk=10000
+NodeName=juju-c9fc6f-5 NodeAddr=10.152.28.51 CPUs=1 RealMemory=1000 TmpDisk=10000
+
+#
+# Down node configurations
+#
+DownNodes=juju-c9fc6f-5 State=DOWN Reason="Maintenance Mode"
+
+#
+# Partition configurations
+#
+PartitionName=DEFAULT MaxTime=30 MaxNodes=10 State=UP
+PartitionName=batch Nodes=juju-c9fc6f-2,juju-c9fc6f-3,juju-c9fc6f-4,juju-c9fc6f-5 MinNodes=4 MaxTime=120 AllowGroups=admin
+"""
+
+EXAMPLE_SLURMDBD_CONFIG = """#
+# `slurmdbd.conf` file generated at 2024-01-30 17:18:36.171652 by slurmutils.
+#
+ArchiveEvents=yes
+ArchiveJobs=yes
+ArchiveResvs=yes
+ArchiveSteps=no
+ArchiveTXN=no
+ArchiveUsage=no
+ArchiveScript=/usr/sbin/slurm.dbd.archive
+AuthInfo=/var/run/munge/munge.socket.2
+AuthType=auth/munge
+AuthAltTypes=auth/jwt
+AuthAltParameters=jwt_key=16549684561684@
+DbdHost=slurmdbd-0
+DbdBackupHost=slurmdbd-1
+DebugLevel=info
+PluginDir=/all/these/cool/plugins
+PurgeEventAfter=1month
+PurgeJobAfter=12month
+PurgeResvAfter=1month
+PurgeStepAfter=1month
+PurgeSuspendAfter=1month
+PurgeTXNAfter=12month
+PurgeUsageAfter=24month
+LogFile=/var/log/slurmdbd.log
+PidFile=/var/run/slurmdbd.pid
+SlurmUser=slurm
+StoragePass=supersecretpasswd
+StorageType=accounting_storage/mysql
+StorageUser=slurm
+StorageHost=127.0.0.1
+StoragePort=3306
+StorageLoc=slurm_acct_db
+"""
+
+EXAMPLE_CGROUP_CONFIG = """#
+# `cgroup.conf` file generated at 2024-09-18 15:10:44.652017 by slurmutils.
+#
+ConstrainCores=yes
+ConstrainDevices=yes
+ConstrainRAMSpace=yes
+ConstrainSwapSpace=yes
+"""
diff --git a/tests/unit/editors/test_cgroupconfig.py b/tests/unit/editors/test_cgroupconfig.py
index b0c8082..c30cc02 100644
--- a/tests/unit/editors/test_cgroupconfig.py
+++ b/tests/unit/editors/test_cgroupconfig.py
@@ -15,30 +15,23 @@
"""Unit tests for the cgroup.conf editor."""
-import unittest
-from pathlib import Path
-from slurmutils.editors import cgroupconfig
+from constants import EXAMPLE_CGROUP_CONFIG
+from pyfakefs.fake_filesystem_unittest import TestCase
-EXAMPLE_CGROUP_CONF = """#
-# `cgroup.conf` file generated at 2024-09-18 15:10:44.652017 by slurmutils.
-#
-ConstrainCores=yes
-ConstrainDevices=yes
-ConstrainRAMSpace=yes
-ConstrainSwapSpace=yes
-"""
+from slurmutils.editors import cgroupconfig
-class TestCgroupConfigEditor(unittest.TestCase):
+class TestCgroupConfigEditor(TestCase):
"""Unit tests for cgroup.conf file editor."""
def setUp(self) -> None:
- Path("cgroup.conf").write_text(EXAMPLE_CGROUP_CONF)
+ self.setUpPyfakefs()
+ self.fs.create_file("/etc/slurm/cgroup.conf", contents=EXAMPLE_CGROUP_CONFIG)
def test_loads(self) -> None:
"""Test `loads` method of the cgroupconfig module."""
- config = cgroupconfig.loads(EXAMPLE_CGROUP_CONF)
+ config = cgroupconfig.loads(EXAMPLE_CGROUP_CONFIG)
self.assertEqual(config.constrain_cores, "yes")
self.assertEqual(config.constrain_devices, "yes")
self.assertEqual(config.constrain_ram_space, "yes")
@@ -46,24 +39,21 @@ def test_loads(self) -> None:
def test_dumps(self) -> None:
"""Test `dumps` method of the cgroupconfig module."""
- config = cgroupconfig.loads(EXAMPLE_CGROUP_CONF)
+ config = cgroupconfig.loads(EXAMPLE_CGROUP_CONFIG)
# The new config and old config should not be equal since the
# timestamps in the header will be different.
- self.assertNotEqual(cgroupconfig.dumps(config), EXAMPLE_CGROUP_CONF)
+ self.assertNotEqual(cgroupconfig.dumps(config), EXAMPLE_CGROUP_CONFIG)
def test_edit(self) -> None:
"""Test `edit` context manager from the cgroupconfig module."""
- with cgroupconfig.edit("cgroup.conf") as config:
+ with cgroupconfig.edit("/etc/slurm/cgroup.conf") as config:
config.constrain_cores = "no"
config.constrain_devices = "no"
config.constrain_ram_space = "no"
config.constrain_swap_space = "no"
- config = cgroupconfig.load("cgroup.conf")
+ config = cgroupconfig.load("/etc/slurm/cgroup.conf")
self.assertEqual(config.constrain_cores, "no")
self.assertEqual(config.constrain_devices, "no")
self.assertEqual(config.constrain_ram_space, "no")
self.assertEqual(config.constrain_swap_space, "no")
-
- def tearDown(self) -> None:
- Path("cgroup.conf").unlink()
diff --git a/tests/unit/editors/test_editor.py b/tests/unit/editors/test_editor.py
new file mode 100644
index 0000000..4fdc55c
--- /dev/null
+++ b/tests/unit/editors/test_editor.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# Copyright 2024 Canonical Ltd.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 3 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+
+"""Unit tests for base editor functions."""
+
+import os
+import stat
+from pathlib import Path
+
+from constants import EXAMPLE_SLURM_CONFIG
+from pyfakefs.fake_filesystem_unittest import TestCase
+
+from slurmutils.editors import slurmconfig
+from slurmutils.editors.editor import set_file_permissions
+
+
+class TestBaseEditor(TestCase):
+ """Unit tests for base editor functions."""
+
+ def setUp(self) -> None:
+ self.setUpPyfakefs()
+ self.fs.create_file("/etc/slurm/slurm.conf", contents=EXAMPLE_SLURM_CONFIG)
+
+ def test_set_file_permissions(self) -> None:
+ """Test the `set_file_permissions` function."""
+ target = Path("/etc/slurm/slurm.conf")
+ set_file_permissions(target, mode=0o600, user=os.getuid(), group=os.getgid())
+ f_info = target.stat()
+ self.assertEqual("-rw-------", stat.filemode(f_info.st_mode))
+ self.assertEqual(os.getuid(), f_info.st_uid)
+ self.assertEqual(os.getgid(), f_info.st_gid)
+
+ def test_loader_fail(self) -> None:
+ """Test that `FileNotFoundError` is raised when attempting to load non-existent file."""
+ self.fs.remove("/etc/slurm/slurm.conf")
+ with self.assertRaises(FileNotFoundError):
+ slurmconfig.load("/etc/slurm/slurm.conf")
+
+ def test_dumper_first_write(self) -> None:
+ """Test that `dumper` succeeds when there is no pre-existing config file."""
+ self.fs.remove("/etc/slurm/slurm.conf")
+ slurmconfig.dump(slurmconfig.loads(EXAMPLE_SLURM_CONFIG), "/etc/slurm/slurm.conf")
diff --git a/tests/unit/editors/test_slurmconfig.py b/tests/unit/editors/test_slurmconfig.py
index 86abe5c..037218d 100644
--- a/tests/unit/editors/test_slurmconfig.py
+++ b/tests/unit/editors/test_slurmconfig.py
@@ -15,72 +15,24 @@
"""Unit tests for the slurm.conf editor."""
-import unittest
-from pathlib import Path
+
+from constants import EXAMPLE_SLURM_CONFIG
+from pyfakefs.fake_filesystem_unittest import TestCase
from slurmutils.editors import slurmconfig
from slurmutils.models import DownNodes, Node, Partition
-example_slurm_conf = """#
-# `slurm.conf` file generated at 2024-01-30 17:18:36.171652 by slurmutils.
-#
-SlurmctldHost=juju-c9fc6f-0(10.152.28.20)
-SlurmctldHost=juju-c9fc6f-1(10.152.28.100)
-
-ClusterName=charmed-hpc
-AuthType=auth/munge
-Epilog=/usr/local/slurm/epilog
-Prolog=/usr/local/slurm/prolog
-FirstJobId=65536
-InactiveLimit=120
-JobCompType=jobcomp/filetxt
-JobCompLoc=/var/log/slurm/jobcomp
-KillWait=30
-MaxJobCount=10000
-MinJobAge=3600
-PluginDir=/usr/local/lib:/usr/local/slurm/lib
-ReturnToService=0
-SchedulerType=sched/backfill
-SlurmctldLogFile=/var/log/slurm/slurmctld.log
-SlurmdLogFile=/var/log/slurm/slurmd.log
-SlurmctldPort=7002
-SlurmdPort=7003
-SlurmdSpoolDir=/var/spool/slurmd.spool
-StateSaveLocation=/var/spool/slurm.state
-SwitchType=switch/none
-TmpFS=/tmp
-WaitTime=30
-
-#
-# Node configurations
-#
-NodeName=juju-c9fc6f-2 NodeAddr=10.152.28.48 CPUs=1 RealMemory=1000 TmpDisk=10000
-NodeName=juju-c9fc6f-3 NodeAddr=10.152.28.49 CPUs=1 RealMemory=1000 TmpDisk=10000
-NodeName=juju-c9fc6f-4 NodeAddr=10.152.28.50 CPUs=1 RealMemory=1000 TmpDisk=10000
-NodeName=juju-c9fc6f-5 NodeAddr=10.152.28.51 CPUs=1 RealMemory=1000 TmpDisk=10000
-
-#
-# Down node configurations
-#
-DownNodes=juju-c9fc6f-5 State=DOWN Reason="Maintenance Mode"
-#
-# Partition configurations
-#
-PartitionName=DEFAULT MaxTime=30 MaxNodes=10 State=UP
-PartitionName=batch Nodes=juju-c9fc6f-2,juju-c9fc6f-3,juju-c9fc6f-4,juju-c9fc6f-5 MinNodes=4 MaxTime=120 AllowGroups=admin
-"""
-
-
-class TestSlurmConfigEditor(unittest.TestCase):
+class TestSlurmConfigEditor(TestCase):
"""Unit tests for slurm.conf file editor."""
def setUp(self) -> None:
- Path("slurm.conf").write_text(example_slurm_conf)
+ self.setUpPyfakefs()
+ self.fs.create_file("/etc/slurm/slurm.conf", contents=EXAMPLE_SLURM_CONFIG)
def test_loads(self) -> None:
"""Test `loads` method of the slurmconfig module."""
- config = slurmconfig.loads(example_slurm_conf)
+ config = slurmconfig.loads(EXAMPLE_SLURM_CONFIG)
self.assertListEqual(
config.slurmctld_host, ["juju-c9fc6f-0(10.152.28.20)", "juju-c9fc6f-1(10.152.28.100)"]
)
@@ -115,15 +67,15 @@ def test_loads(self) -> None:
def test_dumps(self) -> None:
"""Test `dumps` method of the slurmconfig module."""
- config = slurmconfig.loads(example_slurm_conf)
+ config = slurmconfig.loads(EXAMPLE_SLURM_CONFIG)
# The new config and old config should not be equal since the
# timestamps in the header will be different.
- self.assertNotEqual(slurmconfig.dumps(config), example_slurm_conf)
+ self.assertNotEqual(slurmconfig.dumps(config), EXAMPLE_SLURM_CONFIG)
def test_edit(self) -> None:
"""Test `edit` context manager from the slurmconfig module."""
# Test descriptors for `slurm.conf` configuration options.
- with slurmconfig.edit("slurm.conf") as config:
+ with slurmconfig.edit("/etc/slurm/slurm.conf") as config:
del config.inactive_limit
config.max_job_count = 20000
config.proctrack_type = "proctrack/linuxproc"
@@ -132,7 +84,7 @@ def test_edit(self) -> None:
del config.nodes["juju-c9fc6f-2"]
config.nodes.update(new_node.dict())
- config = slurmconfig.load("slurm.conf")
+ config = slurmconfig.load("/etc/slurm/slurm.conf")
self.assertIsNone(config.inactive_limit)
self.assertEqual(config.max_job_count, "20000")
self.assertEqual(config.proctrack_type, "proctrack/linuxproc")
@@ -142,14 +94,14 @@ def test_edit(self) -> None:
)
self.assertEqual(config.nodes["batch-0"]["NodeAddr"], "10.152.28.48")
- with slurmconfig.edit("slurm.conf") as config:
+ with slurmconfig.edit("/etc/slurm/slurm.conf") as config:
del config.nodes
del config.frontend_nodes
del config.down_nodes
del config.node_sets
del config.partitions
- config = slurmconfig.load("slurm.conf")
+ config = slurmconfig.load("/etc/slurm/slurm.conf")
self.assertDictEqual(config.nodes, {})
self.assertDictEqual(config.frontend_nodes, {})
self.assertListEqual(config.down_nodes, [])
@@ -226,7 +178,7 @@ def test_edit(self) -> None:
),
]
- with slurmconfig.edit("slurm.conf") as config:
+ with slurmconfig.edit("/etc/slurm/slurm.conf") as config:
for node in new_nodes:
config.nodes.update(node.dict())
@@ -287,7 +239,7 @@ def test_update(self):
},
}
- config = slurmconfig.loads(example_slurm_conf)
+ config = slurmconfig.loads(EXAMPLE_SLURM_CONFIG)
updates = slurmconfig.SlurmConfig.from_dict(config_updates)
config.update(updates)
@@ -378,6 +330,3 @@ def test_update(self):
},
},
)
-
- def tearDown(self):
- Path("slurm.conf").unlink()
diff --git a/tests/unit/editors/test_slurmdbdconfig.py b/tests/unit/editors/test_slurmdbdconfig.py
index 4bbf1be..c8b6446 100644
--- a/tests/unit/editors/test_slurmdbdconfig.py
+++ b/tests/unit/editors/test_slurmdbdconfig.py
@@ -15,57 +15,23 @@
"""Unit tests for the slurmdbd.conf editor."""
-import unittest
-from pathlib import Path
-from slurmutils.editors import slurmdbdconfig
+from constants import EXAMPLE_SLURMDBD_CONFIG
+from pyfakefs.fake_filesystem_unittest import TestCase
-example_slurmdbd_conf = """#
-# `slurmdbd.conf` file generated at 2024-01-30 17:18:36.171652 by slurmutils.
-#
-ArchiveEvents=yes
-ArchiveJobs=yes
-ArchiveResvs=yes
-ArchiveSteps=no
-ArchiveTXN=no
-ArchiveUsage=no
-ArchiveScript=/usr/sbin/slurm.dbd.archive
-AuthInfo=/var/run/munge/munge.socket.2
-AuthType=auth/munge
-AuthAltTypes=auth/jwt
-AuthAltParameters=jwt_key=16549684561684@
-DbdHost=slurmdbd-0
-DbdBackupHost=slurmdbd-1
-DebugLevel=info
-PluginDir=/all/these/cool/plugins
-PurgeEventAfter=1month
-PurgeJobAfter=12month
-PurgeResvAfter=1month
-PurgeStepAfter=1month
-PurgeSuspendAfter=1month
-PurgeTXNAfter=12month
-PurgeUsageAfter=24month
-LogFile=/var/log/slurmdbd.log
-PidFile=/var/run/slurmdbd.pid
-SlurmUser=slurm
-StoragePass=supersecretpasswd
-StorageType=accounting_storage/mysql
-StorageUser=slurm
-StorageHost=127.0.0.1
-StoragePort=3306
-StorageLoc=slurm_acct_db
-"""
+from slurmutils.editors import slurmdbdconfig
-class TestSlurmdbdConfigEditor(unittest.TestCase):
+class TestSlurmdbdConfigEditor(TestCase):
"""Unit tests for the slurmdbd.conf file editor."""
def setUp(self) -> None:
- Path("slurmdbd.conf").write_text(example_slurmdbd_conf)
+ self.setUpPyfakefs()
+ self.fs.create_file("/etc/slurm/slurmdbd.conf", contents=EXAMPLE_SLURMDBD_CONFIG)
def test_loads(self) -> None:
"""Test `loads` method of the slurmdbdconfig module."""
- config = slurmdbdconfig.loads(example_slurmdbd_conf)
+ config = slurmdbdconfig.loads(EXAMPLE_SLURMDBD_CONFIG)
self.assertListEqual(config.plugin_dir, ["/all/these/cool/plugins"])
self.assertDictEqual(config.auth_alt_parameters, {"jwt_key": "16549684561684@"})
self.assertEqual(config.slurm_user, "slurm")
@@ -73,26 +39,23 @@ def test_loads(self) -> None:
def test_dumps(self) -> None:
"""Test `dumps` method of the slurmdbdconfig module."""
- config = slurmdbdconfig.loads(example_slurmdbd_conf)
+ config = slurmdbdconfig.loads(EXAMPLE_SLURMDBD_CONFIG)
# The new config and old config should not be equal since the
# timestamps in the header will be different.
- self.assertNotEqual(slurmdbdconfig.dumps(config), example_slurmdbd_conf)
+ self.assertNotEqual(slurmdbdconfig.dumps(config), EXAMPLE_SLURMDBD_CONFIG)
def test_edit(self) -> None:
"""Test `edit` context manager from the slurmdbdconfig module."""
- with slurmdbdconfig.edit("slurmdbd.conf") as config:
+ with slurmdbdconfig.edit("/etc/slurm/slurmdbd.conf") as config:
config.archive_usage = "yes"
config.log_file = "/var/spool/slurmdbd.log"
config.debug_flags = ["DB_EVENT", "DB_JOB", "DB_USAGE"]
del config.auth_alt_types
del config.auth_alt_parameters
- config = slurmdbdconfig.load("slurmdbd.conf")
+ config = slurmdbdconfig.load("/etc/slurm/slurmdbd.conf")
self.assertEqual(config.archive_usage, "yes")
self.assertEqual(config.log_file, "/var/spool/slurmdbd.log")
self.assertListEqual(config.debug_flags, ["DB_EVENT", "DB_JOB", "DB_USAGE"])
self.assertIsNone(config.auth_alt_types)
self.assertIsNone(config.auth_alt_parameters)
-
- def tearDown(self) -> None:
- Path("slurmdbd.conf").unlink()
diff --git a/tox.ini b/tox.ini
index ce0c397..f8389d3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -52,6 +52,7 @@ commands =
description = Run unit tests
deps =
pytest
+ pyfakefs
coverage[toml]
commands =
coverage run \