Repository: aristanetworks/anta (python)

Issue:
anta/runner.py throws unhandled exception ValueError: not allowed to raise maximum limit
This seems to be dependent on the underlying OS. Here two samples from Ubuntu (all good) and Rocky9 (fail).

Ubuntu:
```shell
$> docker run --rm python:3.12-slim python -c "import resource; print(resource.getrlimit(resource.RLIMIT_NOFILE))"
(1048576, 1048576)
$> docker run --rm python:3.12-slim python -c "import resource; resource.setrlimit(resource.RLIMIT_NOFILE, resource.getrlimit(resource.RLIMIT_NOFILE))"
$> echo $?
0
```

Rocky9:
```shell
$> docker run -rm python:3.12-slim python -c "import resource; print(resource.getrlimit(resource.RLIMIT_NOFILE))"
(1073741816, 1073741816)

$> docker run --rm python:3.12-slim python -c "import resource; resource.setrlimit(resource.RLIMIT_NOFILE, resource.getrlimit(resource.RLIMIT_NOFILE))"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ValueError: not allowed to raise maximum limit
```

I guess that at the very minimum we should catch the exception. But IMHO we should relay in very platform specific features.

Pull request description:
fix(anta): Catch ValueError in call to setrlimit if can't set RLIMIT_NOFILE.
# Description

Catch ValueError in call to setrlimit if can't set RLIMIT_NOFILE

Fixes #1135

# Checklist:

<!-- Delete not relevant items !-->

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have run pre-commit for code linting and typing (`pre-commit run`)
- [x] New and existing unit tests pass locally with my changes (`tox -e testenv`)


Patch:
diff --git a/anta/runner.py b/anta/runner.py
index 84e27a13..c5880ff6 100644
--- a/anta/runner.py
+++ b/anta/runner.py
@@ -53,7 +53,10 @@ if os.name == "posix":
         logger.debug("Initial limit numbers for open file descriptors for the current ANTA process: Soft Limit: %s | Hard Limit: %s", limits[0], limits[1])
         nofile = min(limits[1], nofile)
         logger.debug("Setting soft limit for open file descriptors for the current ANTA process to %s", nofile)
-        resource.setrlimit(resource.RLIMIT_NOFILE, (nofile, limits[1]))
+        try:
+            resource.setrlimit(resource.RLIMIT_NOFILE, (nofile, limits[1]))
+        except ValueError as exception:
+            logger.warning("Failed to set soft limit for open file descriptors for the current ANTA process: %s", exc_to_str(exception))
         return resource.getrlimit(resource.RLIMIT_NOFILE)
 
 


Test patch:
diff --git a/tests/units/test_runner.py b/tests/units/test_runner.py
index 1b9c40c8..ca794863 100644
--- a/tests/units/test_runner.py
+++ b/tests/units/test_runner.py
@@ -106,7 +106,7 @@ def test_adjust_rlimit_nofile_valid_env(caplog: pytest.LogCaptureFixture) -> Non
 
 @pytest.mark.skipif(os.name != "posix", reason="Cannot run this test on Windows")
 def test_adjust_rlimit_nofile_invalid_env(caplog: pytest.LogCaptureFixture) -> None:
-    """Test adjust_rlimit_nofile with valid environment variables."""
+    """Test adjust_rlimit_nofile with invalid environment variables."""
     with (
         caplog.at_level(logging.DEBUG),
         patch.dict("os.environ", {"ANTA_NOFILE": "invalid"}),
@@ -138,6 +138,39 @@ def test_adjust_rlimit_nofile_invalid_env(caplog: pytest.LogCaptureFixture) -> N
         setrlimit_mock.assert_called_once_with(resource.RLIMIT_NOFILE, (16384, 1048576))
 
 
+@pytest.mark.skipif(os.name != "posix", reason="Cannot run this test on Windows")
+def test_adjust_rlimit_nofile_value_error(caplog: pytest.LogCaptureFixture) -> None:
+    """Test adjust_rlimit_nofile with invalid environment variables."""
+    with (
+        caplog.at_level(logging.DEBUG),
+        patch.dict("os.environ", {"ANTA_NOFILE": "666"}),
+        patch("anta.runner.resource.getrlimit") as getrlimit_mock,
+        patch("anta.runner.resource.setrlimit") as setrlimit_mock,
+    ):
+        # Simulate the default system limits
+        system_limits = (8192, 1048576)
+
+        # Setup getrlimit mock return value
+        getrlimit_mock.return_value = system_limits
+
+        # Simulate setrlimit behavior raising ValueError
+        def side_effect_setrlimit(_resource_id: int, _limits: tuple[int, int]) -> None:
+            msg = "not allowed to raise maximum limit"
+            raise ValueError(msg)
+
+        setrlimit_mock.side_effect = side_effect_setrlimit
+
+        result = adjust_rlimit_nofile()
+
+        # Assert the limits were *NOT* updated as expected
+        assert result == system_limits
+        assert "Initial limit numbers for open file descriptors for the current ANTA process: Soft Limit: 8192 | Hard Limit: 1048576" in caplog.text
+        assert caplog.records[-1].levelname == "WARNING"
+        assert "Failed to set soft limit for open file descriptors for the current ANTA process" in caplog.records[-1].getMessage()
+
+        setrlimit_mock.assert_called_once_with(resource.RLIMIT_NOFILE, (666, 1048576))
+
+
 @pytest.mark.skipif(os.name == "posix", reason="Run this test on Windows only")
 async def test_check_runner_log_for_windows(caplog: pytest.LogCaptureFixture, inventory: AntaInventory) -> None:
     """Test log output for Windows host regarding rlimit."""