Skip to content

Commit

Permalink
Add execute_reboot dbus_interface (#164)
Browse files Browse the repository at this point in the history
As part of sonic-net/sonic-gnmi#286 changes, we require dbus support for executing HALT method.

This PR adds support for execute_reboot for invoking reboot methods.
  • Loading branch information
vvolam authored Nov 8, 2024
1 parent fec6080 commit ff73070
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
22 changes: 22 additions & 0 deletions host_modules/systemd_service.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
"""Systemd service handler"""

from enum import Enum
from host_modules import host_service
import subprocess

MOD_NAME = 'systemd'
ALLOWED_SERVICES = ['snmp', 'swss', 'dhcp_relay', 'radv', 'restapi', 'lldp', 'sshd', 'pmon', 'rsyslog', 'telemetry']
EXIT_FAILURE = 1

# Define an Enum for Reboot Methods which are defined as in
# https://github.com/openconfig/gnoi/blob/main/system/system.pb.go#L27
class RebootMethod(Enum):
COLD = 1
HALT = 3

class SystemdService(host_service.HostModule):
"""
Expand Down Expand Up @@ -48,3 +54,19 @@ def stop_service(self, service):
if result.returncode:
msg = result.stderr.decode()
return result.returncode, msg

@host_service.method(host_service.bus_name(MOD_NAME), in_signature='i', out_signature='is')
def execute_reboot(self, rebootmethod):
if rebootmethod == RebootMethod.COLD:
cmd = ['/usr/local/bin/reboot']
elif rebootmethod == RebootMethod.HALT:
cmd = ['/usr/local/bin/reboot','-p']
else:
return EXIT_FAILURE, "{}: Invalid reboot method: {}".format(MOD_NAME, rebootmethod)

result = subprocess.run(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
msg = ''
if result.returncode:
msg = result.stderr.decode()

return result.returncode, msg
54 changes: 54 additions & 0 deletions tests/host_modules/systemd_service_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,57 @@ def test_service_stop_empty(self, MockInit, MockBusName, MockSystemBus):
ret, msg = systemd_service_stub.stop_service(service)
assert ret == 1
assert "stop_service called with no service specified" in msg

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
def test_execute_reboot_cold(self, MockInit, MockBusName, MockSystemBus):
# Mock subprocess.run
with mock.patch("subprocess.run") as mock_run:
# Mock the result of subprocess.run
res_mock = mock.Mock()
test_ret = 0
test_msg = b"Succeeded"
res_mock.configure_mock(returncode=test_ret, stderr=test_msg)
mock_run.return_value = res_mock

method = systemd_service.RebootMethod.COLD
systemd_service_stub = systemd_service.SystemdService(systemd_service.MOD_NAME)

# Execute the reboot method
ret, msg = systemd_service_stub.execute_reboot(method)

# Assert the correct command was called
call_args = mock_run.call_args[0][0]
assert "/usr/local/bin/reboot" in call_args, f"Expected 'reboot' command, but got: {call_args}"

# Assert the return values are correct
assert ret == test_ret, f"Expected return code {test_ret}, got {ret}"
assert msg == "", f"Expected return message '', got {msg}"

@mock.patch("dbus.SystemBus")
@mock.patch("dbus.service.BusName")
@mock.patch("dbus.service.Object.__init__")
def test_execute_reboot_halt(self, MockInit, MockBusName, MockSystemBus):
# Mock subprocess.run
with mock.patch("subprocess.run") as mock_run:
# Mock the result of subprocess.run
res_mock = mock.Mock()
test_ret = 0
test_msg = b"Succeeded"
res_mock.configure_mock(returncode=test_ret, stderr=test_msg)
mock_run.return_value = res_mock

method = systemd_service.RebootMethod.HALT
systemd_service_stub = systemd_service.SystemdService(systemd_service.MOD_NAME)

# Execute the reboot method
ret, msg = systemd_service_stub.execute_reboot(method)

# Assert the correct command was called
call_args = mock_run.call_args[0][0]
assert "/usr/local/bin/reboot" in call_args, f"Expected 'reboot' command, but got: {call_args}"

# Assert the return values are correct
assert ret == test_ret, f"Expected return code {test_ret}, got {ret}"
assert msg == "", f"Expected return message '', got {msg}"

0 comments on commit ff73070

Please sign in to comment.