[VOL-3656]: Implemented StopManagingDevice DMI API
Change-Id: Idce337f229af51a07022878cb32cc49c899fa579
diff --git a/docs/source/DMI_Server_README.md b/docs/source/DMI_Server_README.md
index 0fb41ff..1f3e660 100755
--- a/docs/source/DMI_Server_README.md
+++ b/docs/source/DMI_Server_README.md
@@ -166,6 +166,12 @@
}
}
```
+### StopManagingDevice API
+``` sh
+grpcurl -plaintext -d '{"name":"SomeOlt"}' 172.17.0.2:50075 dmi.NativeHWManagementService.StopManagingDevice{
+ "status": "OK_STATUS"
+}
+```
### List NativeMetricsManagementService APIs
``` sh
$ grpcurl -plaintext 172.17.0.2:50075 list dmi.NativeMetricsManagementService
@@ -270,4 +276,4 @@
]
}
}
-```
+```
\ No newline at end of file
diff --git a/internal/bbsim/dmiserver/dmi_api_server.go b/internal/bbsim/dmiserver/dmi_api_server.go
index 3fed692..f64f801 100755
--- a/internal/bbsim/dmiserver/dmi_api_server.go
+++ b/internal/bbsim/dmiserver/dmi_api_server.go
@@ -74,10 +74,6 @@
go func() { _ = grpcServer.Serve(lis) }()
logger.Debugf("DMI grpc Server listening on %v", address)
- //buffer upto 100 metrics
- dms.metricChannel = make(chan interface{}, 100)
-
- StartMetricGenerator(dms)
return grpcServer, nil
}
diff --git a/internal/bbsim/dmiserver/dmi_hw_mgmt.go b/internal/bbsim/dmiserver/dmi_hw_mgmt.go
index 30c27f0..cf6410d 100755
--- a/internal/bbsim/dmiserver/dmi_hw_mgmt.go
+++ b/internal/bbsim/dmiserver/dmi_hw_mgmt.go
@@ -33,6 +33,10 @@
"google.golang.org/grpc/status"
)
+const (
+ metricChannelSize = 100
+)
+
func getUUID(seed string) string {
return guuid.NewMD5(guuid.Nil, []byte(seed)).String()
}
@@ -61,6 +65,10 @@
dms.ponTransceiverUuids = make([]string, olt.NumPon)
dms.ponTransceiverCageUuids = make([]string, olt.NumPon)
+ // Start device metrics generator
+ dms.metricChannel = make(chan interface{}, metricChannelSize)
+ StartMetricGenerator(dms)
+
var components []*dmi.Component
// Create and store the component for transceivers and transceiver cages
@@ -244,8 +252,36 @@
}
//StopManagingDevice stops management of a device and cleans up any context and caches for that device
-func (dms *DmiAPIServer) StopManagingDevice(context.Context, *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "rpc StopManagingDevice not implemented")
+func (dms *DmiAPIServer) StopManagingDevice(ctx context.Context, req *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
+ logger.Debugf("StopManagingDevice API invoked")
+ if req == nil {
+ return &dmi.StopManagingDeviceResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.Reason_UNKNOWN_DEVICE}, status.Errorf(codes.FailedPrecondition, "request is empty")
+ }
+
+ if req.Name == "" {
+ return &dmi.StopManagingDeviceResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.Reason_UNKNOWN_DEVICE},
+ status.Errorf(codes.InvalidArgument, "'Name' can not be empty in the request")
+ }
+
+ // Stop the components/go routines created
+ StopMetricGenerator()
+
+ if dms.mPublisherCancelFunc != nil {
+ dms.mPublisherCancelFunc()
+ }
+
+ dms.deviceName = ""
+ dms.kafkaEndpoint = ""
+ dms.ipAddress = ""
+ dms.deviceSerial = ""
+ dms.ponTransceiverUuids = nil
+ dms.ponTransceiverCageUuids = nil
+ dms.uuid = ""
+ dms.root = nil
+ dms.metricChannel = nil
+
+ logger.Infof("Stopped managing the device")
+ return &dmi.StopManagingDeviceResponse{Status: dmi.Status_OK_STATUS}, nil
}
//GetPhysicalInventory gets the HW inventory details of the Device
@@ -370,6 +406,11 @@
return status.Errorf(codes.Internal, "stream to send is nil, can not send response from gRPC server")
}
+ //if component list is empty, return error
+ if dms.root == nil {
+ logger.Errorf("Error occurred, device is not managed")
+ return status.Errorf(codes.Internal, "Error occurred, device is not managed, please start managing device")
+ }
// Search for the component and return it
c := findComponent(dms.root.Children, req.ComponentUuid.Uuid)
diff --git a/internal/bbsim/dmiserver/dmi_metrics_generator.go b/internal/bbsim/dmiserver/dmi_metrics_generator.go
index f7bbd03..09deace 100755
--- a/internal/bbsim/dmiserver/dmi_metrics_generator.go
+++ b/internal/bbsim/dmiserver/dmi_metrics_generator.go
@@ -17,6 +17,8 @@
package dmiserver
import (
+ "context"
+ log "github.com/sirupsen/logrus"
"math/rand"
"sync"
"time"
@@ -25,6 +27,9 @@
dmi "github.com/opencord/device-management-interface/go/dmi"
)
+//MetricGenerationFunc to generate the metrics to the kafka bus
+type MetricGenerationFunc func(*dmi.Component, *DmiAPIServer) *dmi.Metric
+
// MetricTriggerConfig is the configuration of a metric and the time at which it will be exported
type MetricTriggerConfig struct {
cfg dmi.MetricConfig
@@ -36,13 +41,14 @@
apiSrv *DmiAPIServer
configuredMetrics map[dmi.MetricNames]MetricTriggerConfig
access sync.Mutex
+ mgCancelFunc context.CancelFunc
}
var dmiMG DmiMetricsGenerator
//StartMetricGenerator starts the metric generator
func StartMetricGenerator(apiSrv *DmiAPIServer) {
-
+ log.Debugf("StartMetricGenerator invoked")
// Seed the rand for use later on
rand.Seed(time.Now().UnixNano())
@@ -105,8 +111,32 @@
t: time.Unix(0, 0),
}
- go func() {
- for {
+ StartGeneratingMetrics()
+}
+
+// StartGeneratingMetrics starts the goroutine which submits metrics to the metrics channel
+func StartGeneratingMetrics() {
+ if dmiMG.apiSrv == nil {
+ // Metric Generator is not yet initialized/started.
+ // Means that the device is not managed on the DMI interface
+ return
+ }
+
+ // initialize a new context
+ var mgCtx context.Context
+ mgCtx, dmiMG.mgCancelFunc = context.WithCancel(context.Background())
+
+ go generateMetrics(mgCtx)
+}
+
+func generateMetrics(ctx context.Context) {
+loop:
+ for {
+ select {
+ case <-ctx.Done():
+ log.Infof("Stopping generation of metrics ")
+ break loop
+ default:
c := make(map[dmi.MetricNames]MetricTriggerConfig)
dmiMG.access.Lock()
@@ -184,7 +214,7 @@
}
time.Sleep(1 * time.Second)
}
- }()
+ }
}
func sendOutMetric(metric interface{}, apiSrv *DmiAPIServer) {
@@ -344,3 +374,22 @@
}
return nil
}
+
+// StopGeneratingMetrics stops the goroutine which submits metrics to the metrics channel
+func StopGeneratingMetrics() {
+ if dmiMG.mgCancelFunc != nil {
+ dmiMG.mgCancelFunc()
+ }
+}
+
+// StopMetricGenerator stops the generation of metrics and cleans up all local context
+func StopMetricGenerator() {
+ logger.Debugf("StopMetricGenerator invoked")
+
+ StopGeneratingMetrics()
+
+ dmiMG.access.Lock()
+ // reset it to an empty map
+ dmiMG.configuredMetrics = make(map[dmi.MetricNames]MetricTriggerConfig)
+ dmiMG.access.Unlock()
+}
diff --git a/internal/bbsim/dmiserver/dmi_metrics_mgmt.go b/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
index 3f33941..cb88cc7 100755
--- a/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
+++ b/internal/bbsim/dmiserver/dmi_metrics_mgmt.go
@@ -45,7 +45,9 @@
if req == nil || req.Operation == nil {
return &dmi.MetricsConfigurationResponse{
- Status: dmi.Status_UNDEFINED_STATUS,
+ Status: dmi.Status_ERROR_STATUS,
+ //TODO reason must be INVALID_PARAMS, currently this is available in Device Management interface (DMI),
+ // change below reason with type INVALID_PARAMS once DMI is updated
Reason: dmi.Reason_UNDEFINED_REASON,
}, status.Errorf(codes.FailedPrecondition, "request is nil")
}
@@ -77,10 +79,20 @@
if req == nil || req.GetMetricId() < 0 {
return &dmi.GetMetricResponse{
Status: dmi.Status_ERROR_STATUS,
+ //TODO reason must be INVALID_PARAMS, currently this is available in Device Management interface (DMI),
+ // change below reason with type INVALID_PARAMS once DMI is updated
Reason: dmi.Reason_UNDEFINED_REASON,
Metric: &dmi.Metric{},
}, status.Errorf(codes.FailedPrecondition, "request is nil")
}
+
+ if dms.root == nil {
+ return &dmi.GetMetricResponse{
+ Status: dmi.Status_ERROR_STATUS,
+ Reason: dmi.Reason_INTERNAL_ERROR,
+ Metric: &dmi.Metric{},
+ }, status.Errorf(codes.FailedPrecondition, "Device is not managed, please start managing device to get the metric")
+ }
comp := findComponent(dms.root.Children, req.MetaData.ComponentUuid.Uuid)
metric := getMetric(comp, req.GetMetricId())
return &dmi.GetMetricResponse{