diff --git a/common_utils/context.go b/common_utils/context.go index a9059f4a..09bff486 100644 --- a/common_utils/context.go +++ b/common_utils/context.go @@ -54,6 +54,7 @@ const ( DBUS_STOP_SERVICE DBUS_RESTART_SERVICE DBUS_FILE_STAT + DBUS_HALT_SYSTEM COUNTER_SIZE ) @@ -91,6 +92,8 @@ func (c CounterType) String() string { return "DBUS restart service" case DBUS_FILE_STAT: return "DBUS file stat" + case DBUS_HALT_SYSTEM: + return "DBUS halt system" default: return "" } diff --git a/gnmi_server/gnoi.go b/gnmi_server/gnoi.go index f11a9a81..4c3aad6c 100644 --- a/gnmi_server/gnoi.go +++ b/gnmi_server/gnoi.go @@ -139,6 +139,20 @@ func (srv *SystemServer) KillProcess(ctx context.Context, req *gnoi_system_pb.Ki return &resp, nil } +func HaltSystem() error { + sc,err := ssc.NewDbusClient() + if err != nil { + return err + } + + log.V(2).Infof("Halting the system..") + err = sc.HaltSystem() + if err != nil { + log.V(2).Infof("Failed to Halt the system %v", err); + } + return err +} + func RebootSystem(fileName string) error { log.V(2).Infof("Rebooting with %s...", fileName) sc, err := ssc.NewDbusClient() @@ -158,18 +172,30 @@ func (srv *SystemServer) Reboot(ctx context.Context, req *gnoi_system_pb.RebootR } log.V(1).Info("gNOI: Reboot") log.V(1).Info("Request:", req) - log.V(1).Info("Reboot system now, delay is ignored...") - // TODO: Support GNOI reboot delay - // Delay in nanoseconds before issuing reboot. - // https://github.com/openconfig/gnoi/blob/master/system/system.proto#L102-L115 - config_db_json, err := io.ReadFile(fileName) - if errors.Is(err, os.ErrNotExist) { - fileName = "" - } - err = RebootSystem(string(config_db_json)) - if err != nil { - return nil, err + + // Check the reboot type + switch req.GetMethod() { + case gnoi_system_pb.RebootMethod_HALT: + log.V(1).Info("Reboot method is HALT. Halting the system...") + err = HaltSystem() + if err != nil { + return nil, err + } + default: + log.V(1).Info("Reboot system now, delay is ignored...") + // TODO: Support GNOI reboot delay + // Delay in nanoseconds before issuing reboot. + // https://github.com/openconfig/gnoi/blob/master/system/system.proto#L102-L115 + config_db_json, err := io.ReadFile(fileName) + if errors.Is(err, os.ErrNotExist) { + fileName = "" + } + err = RebootSystem(string(config_db_json)) + if err != nil { + return nil, err + } } + var resp gnoi_system_pb.RebootResponse return &resp, nil } diff --git a/sonic_service_client/dbus_client.go b/sonic_service_client/dbus_client.go index 48291570..51777099 100644 --- a/sonic_service_client/dbus_client.go +++ b/sonic_service_client/dbus_client.go @@ -19,6 +19,7 @@ type Service interface { StopService(service string) error RestartService(service string) error GetFileStat(path string) (map[string]string, error) + HaltSystem() error } type DbusClient struct { @@ -191,3 +192,21 @@ func (c *DbusClient) GetFileStat(path string) (map[string]string, error) { data, _ := result.(map[string]string) return data, nil } + +func (c *DbusClient) HaltSystem() error { + // Increment the counter for the DBUS_HALT_SYSTEM event + common_utils.IncCounter(common_utils.DBUS_HALT_SYSTEM) + + // Set the module name and update the D-Bus properties + modName := "systemd" + busName := c.busNamePrefix + modName + busPath := c.busPathPrefix + modName + intName := c.intNamePrefix + modName + ".execute_reboot" + + //Set the method to HALT(3) the system + const RebootMethod_HALT = 3 + + // Invoke the D-Bus API to execute the halt command + _, err := DbusApi(busName, busPath, intName, 10, RebootMethod_HALT) + return err +} diff --git a/test/test_gnoi.py b/test/test_gnoi.py index 61b7c067..f8ceccf3 100644 --- a/test/test_gnoi.py +++ b/test/test_gnoi.py @@ -21,6 +21,17 @@ def test_gnoi_reboot(self): assert ret == 0, 'Fail to read counter' assert new_cnt == old_cnt+1, 'DBUS API is not invoked' + def test_gnoi_reboot_halt(self): + ret, old_cnt = gnmi_dump('DBUS halt system') + assert ret == 0, 'Fail to read counter' + + ret, msg = gnoi_reboot(3, 0, 'Test halt system') + assert ret == 0, msg + + ret, new_cnt = gnmi_dump('DBUS halt system') + assert ret == 0, 'Fail to read counter' + assert new_cnt == old_cnt+1, 'DBUS API is not invoked' + def test_gnoi_rebootstatus(self): ret, msg = gnoi_rebootstatus() assert ret != 0, 'RebootStatus should fail' + msg @@ -74,4 +85,4 @@ def test_gnoi_restartprocess_invalid(self): ret, new_cnt = gnmi_dump('DBUS restart service') assert ret == 0, 'Fail to read counter' - assert new_cnt == old_cnt, 'DBUS API invoked unexpectedly' \ No newline at end of file + assert new_cnt == old_cnt, 'DBUS API invoked unexpectedly'