Revise ServiceManagerV1.Status API

Allows querying for the status of all/multiple services at once.
Reply becomes a map[string]string, where the key is the service name
and the value represents the name of the state the service is in
(instead of returning just RUNNING/STOPPED).
This commit is contained in:
ionutboangiu
2025-02-04 17:13:05 +02:00
committed by Dan Christian Bogos
parent 712aeb0d4a
commit 1d536c6390
3 changed files with 35 additions and 37 deletions

View File

@@ -32,14 +32,14 @@ type ServiceManagerV1 struct {
ping
}
func (servManager *ServiceManagerV1) StartService(ctx *context.Context, args *servmanager.ArgsServiceID, reply *string) (err error) {
func (servManager *ServiceManagerV1) StartService(ctx *context.Context, args *servmanager.ArgsServiceID, reply *string) error {
return servManager.sm.V1StartService(ctx, args, reply)
}
func (servManager *ServiceManagerV1) StopService(ctx *context.Context, args *servmanager.ArgsServiceID, reply *string) (err error) {
func (servManager *ServiceManagerV1) StopService(ctx *context.Context, args *servmanager.ArgsServiceID, reply *string) error {
return servManager.sm.V1StopService(ctx, args, reply)
}
func (servManager *ServiceManagerV1) ServiceStatus(ctx *context.Context, args *servmanager.ArgsServiceID, reply *string) (err error) {
func (servManager *ServiceManagerV1) ServiceStatus(ctx *context.Context, args *servmanager.ArgsServiceID, reply *map[string]string) error {
return servManager.sm.V1ServiceStatus(ctx, args, reply)
}

View File

@@ -144,15 +144,16 @@ func testSrvMngPing(t *testing.T) {
Run the following tests for each service:
- ping before enabling service (expect can't find service error)
- query for service status (expect "STOPPED" reply)
- query for service status (expect service to be in state "SERVICE_DOWN")
- start the service
- query for service status (expect "RUNNING" reply)
- query for service status (expect service to be in state "SERVICE_UP")
- ping (expect "Pong")
- stop service
- query for service status (expect "STOPPED" reply)
- query for service status (expect service to be in state "SERVICE_DOWN" reply)
- ping after stopping service (expect "can't find service" error)
*/
var statusReply map[string]string
for serviceID, serviceMethod := range serviceToMethod {
t.Run(fmt.Sprintf("test for service %s", serviceID), func(t *testing.T) {
rpcErr := fmt.Sprintf("rpc: can't find service %s", serviceMethod)
@@ -166,10 +167,10 @@ func testSrvMngPing(t *testing.T) {
}
if err := srvMngRPC.Call(context.Background(), utils.ServiceManagerV1ServiceStatus, args,
&reply); err != nil {
&statusReply); err != nil {
t.Error(err)
} else if reply != utils.StoppedCaps {
t.Errorf("Unexpected reply: %s", reply)
} else if statusReply[serviceID] != utils.StateServiceDOWN {
t.Errorf("Unexpected reply: %s", utils.ToJSON(statusReply))
}
if err := srvMngRPC.Call(context.Background(), utils.ServiceManagerV1StartService, args,
@@ -180,10 +181,10 @@ func testSrvMngPing(t *testing.T) {
}
if err := srvMngRPC.Call(context.Background(), utils.ServiceManagerV1ServiceStatus, args,
&reply); err != nil {
&statusReply); err != nil {
t.Error(err)
} else if reply != utils.RunningCaps {
t.Errorf("Unexpected reply: %s", reply)
} else if statusReply[serviceID] != utils.StateServiceUP {
t.Errorf("Unexpected reply: %s", utils.ToJSON(statusReply))
}
if err := srvMngRPC.Call(context.Background(), serviceMethod, nil,
@@ -201,10 +202,10 @@ func testSrvMngPing(t *testing.T) {
}
if err := srvMngRPC.Call(context.Background(), utils.ServiceManagerV1ServiceStatus, args,
&reply); err != nil {
&statusReply); err != nil {
t.Error(err)
} else if reply != utils.StoppedCaps {
t.Errorf("Unexpected reply: %s", reply)
} else if statusReply[serviceID] != utils.StateServiceDOWN {
t.Errorf("Unexpected reply: %s", utils.ToJSON(statusReply))
}
if err := srvMngRPC.Call(context.Background(), serviceMethod, nil,

View File

@@ -21,6 +21,7 @@ package servmanager
import (
"fmt"
"slices"
"strings"
"sync"
"github.com/cgrates/birpc/context"
@@ -183,21 +184,27 @@ func (m *ServiceManager) V1StopService(ctx *context.Context, args *ArgsServiceID
return
}
// V1ServiceStatus returns the service status
func (m *ServiceManager) V1ServiceStatus(ctx *context.Context, args *ArgsServiceID, reply *string) error {
// V1ServiceStatus returns the current state of the specified services.
func (m *ServiceManager) V1ServiceStatus(ctx *context.Context, args *ArgsServiceID, reply *map[string]string) error {
m.RLock()
defer m.RUnlock()
svc := m.registry.Lookup(args.ServiceID)
if svc == nil {
return utils.ErrUnsupportedServiceID
}
if IsServiceInState(svc, utils.StateServiceUP) {
*reply = utils.RunningCaps
} else {
*reply = utils.StoppedCaps
states := make(map[string]string)
switch args.ServiceID {
case utils.MetaAll:
for _, svc := range m.registry.List() {
states[svc.ServiceName()] = State(svc)
}
default:
ids := strings.Split(args.ServiceID, utils.FieldsSep)
for _, id := range ids {
svc := m.registry.Lookup(id)
if svc == nil {
return fmt.Errorf("unsupported service ID: %q", id)
}
states[id] = State(svc)
}
}
*reply = states
return nil
}
@@ -299,16 +306,6 @@ func toggleService(id string, status bool, srvMngr *ServiceManager) (err error)
return
}
// IsServiceInState performs a non-blocking check to determine if a service is in the specified state.
func IsServiceInState(svc Service, state string) bool {
select {
case <-svc.StateChan(state):
return true
default:
return false
}
}
// MustSetState changes a service's state, panicking if it fails.
func MustSetState(svc Service, state string) {
if err := SetState(svc, state); err != nil {