Repository: cobbler/cobbler

Issue:
Cobbler doesn't restart dhcpd6 daemon
### Describe the bug

<!--- A clear and concise description of what the bug is. -->
Cobbler doesn't restart dhcpd daemon for ipv6
<!--- HINT: You can paste gist.github.com links for long logs or larger files -->

### Steps to reproduce

1. Enable IPV6 support in cobbler settings.conf
2. Do `cobbler sync`
3. Only ipv4 version of daemon is restarted

### Expected behavior

<!--- A clear and concise description of what you expected to happen. -->

### Cobbler version

<!--- Paste output from `cobbler version` -->
````paste below
3.4.0
````

### Operating system
Rocky 8.6
<!--- On which operating system do you use Cobbler? -->

### Cobbler log

<!--- Paste (partial) output from `/var/log/cobbler/cobbler.log` -->
````paste below
````

### Screenshots

<!--- If applicable, add screenshots to help explain your problem. -->

### Additional information

<!--- Add any other context about the problem here. -->

````
Had not time to chase this issue, adding this issue for the record, will have a look if none will solve this sooner.



Discussion:
As much as I would like to finish up 3.4.0 finally, this bug is important enough to be included in 3.4.0.

Resolving patch:
diff --git a/cobbler/modules/sync_post_restart_services.py b/cobbler/modules/sync_post_restart_services.py
--- a/cobbler/modules/sync_post_restart_services.py
+++ b/cobbler/modules/sync_post_restart_services.py
@@ -43,19 +43,11 @@ def run(api: "CobblerAPI", args: List[str]) -> int:
     has_restarted_dnsmasq = False
 
     ret_code = 0
-    if settings.manage_dhcp:
-        if which_dhcp_module == "managers.isc":
-            if settings.restart_dhcp:
-                ret_code = utils.subprocess_call(["dhcpd", "-t", "-q"], shell=False)
-                if ret_code != 0:
-                    logger.error("dhcpd -t failed")
-                    return 1
-                dhcp_service_name = utils.dhcp_service_name()
-                ret_code = process_management.service_restart(dhcp_service_name)
-        elif which_dhcp_module == "managers.dnsmasq":
-            if settings.restart_dhcp:
-                service_name = "dnsmasq"
-                ret_code = process_management.service_restart(service_name)
+    if settings.manage_dhcp and settings.restart_dhcp:
+        if which_dhcp_module in ("managers.isc", "managers.dnsmasq"):
+            dhcp_module = api.get_module_from_file("dhcp", "module")
+            ret_code = dhcp_module.get_manager(api).restart_service()
+            if which_dhcp_module == "managers.dnsmasq":
                 has_restarted_dnsmasq = True
         else:
             logger.error("unknown DHCP engine: %s", which_dhcp_module)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -501,7 +501,6 @@ def run(self):
 
 
 class Savestate(Statebase):
-
     description = "Backup the current configuration to /tmp/cobbler_settings."
 
     def _copy(self, frm: str, to: str) -> None:
@@ -602,6 +601,7 @@ def run(self):
                 "types-PyYAML",
                 "types-psutil",
                 "types-netaddr",
+                "types-mock",
                 "isort",
             ],
             "test": [


Test patch:
diff --git a/tests/modules/sync_post_restart_services_test.py b/tests/modules/sync_post_restart_services_test.py
--- a/tests/modules/sync_post_restart_services_test.py
+++ b/tests/modules/sync_post_restart_services_test.py
@@ -1,8 +1,11 @@
-from unittest.mock import MagicMock
+from typing import TYPE_CHECKING
 
 from cobbler.api import CobblerAPI
 from cobbler.modules import sync_post_restart_services
 
+if TYPE_CHECKING:
+    from pytest_mock import MockerFixture
+
 
 def test_register():
     # Arrange & Act
@@ -12,19 +15,19 @@ def test_register():
     assert result == "/var/lib/cobbler/triggers/sync/post/*"
 
 
-def test_run(mocker):
+def test_run(mocker: "MockerFixture"):
     # Arrange
     restart_mock = mocker.patch(
         "cobbler.utils.process_management.service_restart", return_value=0
     )
-    api = MagicMock(spec=CobblerAPI)
-    api.get_module_name_from_file.side_effect = ["managers.isc", "managers.bind"]
-    args = None
+    api = mocker.MagicMock(spec=CobblerAPI)
+    api.get_module_name_from_file.side_effect = ["managers.isc", "managers.bind"]  # type: ignore
+    args = []
 
     # Act
     result = sync_post_restart_services.run(api, args)
 
     # Assert
     # FIXME improve assert
-    assert restart_mock.call_count == 2
+    assert restart_mock.call_count == 1
     assert result == 0