blob: 26b15f1e2b2f832102f823c33c7a3c6c38f84bea [file] [log] [blame]
amit.ghosh258d14c2020-10-02 15:13:38 +02001/*
Joey Armstrong2c039362024-02-04 18:51:52 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
amit.ghosh258d14c2020-10-02 15:13:38 +02003
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package dmiserver
18
19import (
20 "context"
21 "fmt"
22
Humera Kousera4442952020-11-23 23:51:19 +053023 "github.com/Shopify/sarama"
Elia Battistone8d1fa42022-04-01 10:47:37 +020024 log "github.com/sirupsen/logrus"
Humera Kousera4442952020-11-23 23:51:19 +053025
amit.ghosh258d14c2020-10-02 15:13:38 +020026 "github.com/golang/protobuf/ptypes/empty"
27 "github.com/golang/protobuf/ptypes/timestamp"
28 "github.com/opencord/bbsim/internal/bbsim/devices"
29 "github.com/opencord/bbsim/internal/common"
30 dmi "github.com/opencord/device-management-interface/go/dmi"
31
32 guuid "github.com/google/uuid"
33 "google.golang.org/grpc/codes"
34 "google.golang.org/grpc/status"
35)
36
Humera Kouser18b275c2020-11-30 11:30:36 +053037const (
hkouser24361d42020-12-14 19:21:47 +053038 kafkaChannelSize = 100
Humera Kouser18b275c2020-11-30 11:30:36 +053039)
40
amit.ghosh258d14c2020-10-02 15:13:38 +020041func getUUID(seed string) string {
42 return guuid.NewMD5(guuid.Nil, []byte(seed)).String()
43}
44
Elia Battistone8d1fa42022-04-01 10:47:37 +020045func getOltName() string {
46 return fmt.Sprintf("%s-%s", common.Config.Olt.Vendor, devices.GetOLT().SerialNumber)
47}
48
49func getOltUUID() *dmi.Uuid {
50 return &dmi.Uuid{
51 Uuid: getUUID(devices.GetOLT().SerialNumber),
52 }
53}
54
55func getCageName(id uint32) string {
56 return fmt.Sprintf("sfp-plus-transceiver-cage-%d", id)
57}
58
59func getCageUUID(id uint32) *dmi.Uuid {
60 return &dmi.Uuid{
61 Uuid: getUUID(fmt.Sprintf("%s-%s", devices.GetOLT().SerialNumber, getCageName(id))),
62 }
63}
64
65func getTransceiverName(id uint32) string {
66 return fmt.Sprintf("sfp-plus-%d", id)
67}
68
69func getTransceiverUUID(id uint32) *dmi.Uuid {
70 return &dmi.Uuid{
71 Uuid: getUUID(fmt.Sprintf("%s-%s", devices.GetOLT().SerialNumber, getTransceiverName(id))),
72 }
73}
74
75func getPonName(id uint32) string {
76 return fmt.Sprintf("pon-%d", id)
77}
78
79func getPonUUID(id uint32) *dmi.Uuid {
80 return &dmi.Uuid{
81 Uuid: getUUID(fmt.Sprintf("%s-%s", devices.GetOLT().SerialNumber, getPonName(id))),
82 }
83}
84
Abhay Kumarc5723cc2023-06-08 12:09:30 +053085// StartManagingDevice establishes connection with the device and does checks to ascertain if the device with passed identity can be managed
amit.ghosh258d14c2020-10-02 15:13:38 +020086func (dms *DmiAPIServer) StartManagingDevice(req *dmi.ModifiableComponent, stream dmi.NativeHWManagementService_StartManagingDeviceServer) error {
87 //Get serial number and generate the UUID based on this serial number. Store this UUID in local cache
88 logger.Debugf("StartManagingDevice() invoked with request %+v", req)
89 if req == nil {
90 return status.Errorf(codes.FailedPrecondition, "request is empty")
91 }
92
93 if req.Name == "" {
94 return status.Errorf(codes.InvalidArgument, "'Name' can not be empty in the request")
95 }
96
97 olt := devices.GetOLT()
98
99 // Uri is the IP address
100 dms.ipAddress = req.GetUri().GetUri()
amit.ghosh258d14c2020-10-02 15:13:38 +0200101
Elia Battistone8d1fa42022-04-01 10:47:37 +0200102 deviceName := getOltName()
103 dms.uuid = getOltUUID()
amit.ghosh258d14c2020-10-02 15:13:38 +0200104
Humera Kouser18b275c2020-11-30 11:30:36 +0530105 // Start device metrics generator
hkouser24361d42020-12-14 19:21:47 +0530106 dms.metricChannel = make(chan interface{}, kafkaChannelSize)
Humera Kouser18b275c2020-11-30 11:30:36 +0530107 StartMetricGenerator(dms)
108
hkouser24361d42020-12-14 19:21:47 +0530109 // Start device event generator
110 dms.eventChannel = make(chan interface{}, kafkaChannelSize)
111 StartEventsGenerator(dms)
112
amit.ghosh258d14c2020-10-02 15:13:38 +0200113 var components []*dmi.Component
114
115 // Create and store the component for transceivers and transceiver cages
Elia Battistone8d1fa42022-04-01 10:47:37 +0200116 for _, trans := range dms.Transceivers {
117 //Make one cage for each of the transceivers
118 cageName := getCageName(trans.ID)
amit.ghosh258d14c2020-10-02 15:13:38 +0200119
120 cage := dmi.Component{
121 Name: cageName,
122 Class: dmi.ComponentType_COMPONENT_TYPE_CONTAINER,
123 Description: "cage",
Elia Battistone8d1fa42022-04-01 10:47:37 +0200124 Uuid: getCageUUID(trans.ID),
125 Parent: deviceName,
126 Children: []*dmi.Component{},
127 }
128
129 //If the transceiver is not plugged in, only the empty cage is created
130 if trans.PluggedIn {
131 transComponent, err := createTransceiverComponent(trans, cageName)
132 if err != nil {
133 logger.Error(err)
134 continue
135 }
136 cage.Children = append(cage.Children, transComponent)
amit.ghosh258d14c2020-10-02 15:13:38 +0200137 }
138
139 components = append(components, &cage)
140 }
141
Humera Kousera4442952020-11-23 23:51:19 +0530142 // create the fans
143 numFans := 2
144 fans := make([]*dmi.Component, numFans)
145
146 for i := 0; i < numFans; i++ {
147 fans[i] = createFanComponent(i + 1)
148 }
149 components = append(components, fans...)
150
hkouser24361d42020-12-14 19:21:47 +0530151 // Create 1 disk, 1 processor, 1 ram, 1 temperature sensor and power supply unit
Humera Kousera4442952020-11-23 23:51:19 +0530152 components = append(components, createDiskComponent(0))
153 components = append(components, createProcessorComponent(0))
154 components = append(components, createMemoryComponent(0))
155 components = append(components, createInnerSurroundingTempComponentSensor(0))
hkouser24361d42020-12-14 19:21:47 +0530156 components = append(components, createPowerSupplyComponent(0))
Humera Kousera4442952020-11-23 23:51:19 +0530157
158 // create the root component
159 dms.root = &dmi.Component{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200160 Name: deviceName,
Humera Kousera4442952020-11-23 23:51:19 +0530161 Class: 0,
162 Description: "",
163 Parent: "",
164 ParentRelPos: 0,
165 Children: components,
Elia Battistone8d1fa42022-04-01 10:47:37 +0200166 SerialNum: olt.SerialNumber,
Humera Kousera4442952020-11-23 23:51:19 +0530167 MfgName: common.Config.Olt.Vendor,
168 IsFru: false,
169 Uri: &dmi.Uri{
170 Uri: dms.ipAddress,
171 },
Elia Battistone8d1fa42022-04-01 10:47:37 +0200172 Uuid: dms.uuid,
Humera Kousera4442952020-11-23 23:51:19 +0530173 State: &dmi.ComponentState{},
174 }
amit.ghosh258d14c2020-10-02 15:13:38 +0200175
Elia Battistone8d1fa42022-04-01 10:47:37 +0200176 logger.Debugf("Generated UUID for the uri %s is %s", dms.ipAddress, dms.uuid.Uuid)
amit.ghosh258d14c2020-10-02 15:13:38 +0200177 response := &dmi.StartManagingDeviceResponse{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200178 Status: dmi.Status_OK_STATUS,
179 DeviceUuid: dms.uuid,
amit.ghosh258d14c2020-10-02 15:13:38 +0200180 }
181
182 err := stream.Send(response)
183 if err != nil {
184 logger.Errorf("Error while sending response to client %v", err.Error())
185 return status.Errorf(codes.Unknown, err.Error())
186 }
187
188 return nil
189}
190
Elia Battistone8d1fa42022-04-01 10:47:37 +0200191func createTransceiverComponent(trans *Transceiver, cageName string) (*dmi.Component, error) {
192 portName := getPonName(trans.ID)
193
194 var rxWavelength, txWavelength []uint32
195
196 if len(trans.Pons) == 0 {
197 return nil, fmt.Errorf("No pons in list for transceiver %d", trans.ID)
198 } else if len(trans.Pons) <= 1 {
199 //Assuming a transceiver with only one PON
200 //has the technology of the PON
201
202 switch trans.Pons[0].Technology {
203 case common.GPON:
204 trans.Technology = dmi.TransceiverType_GPON
205 rxWavelength = []uint32{1490} // nanometers
206 txWavelength = []uint32{1550} // nanometers
207 case common.XGSPON:
208 trans.Technology = dmi.TransceiverType_XGSPON
209 rxWavelength = []uint32{1270} // nanometers
210 txWavelength = []uint32{1577} // nanometers
211 }
212 } else {
213 //Assuming more than one PON for the transceiver
214 //is COMBO PON
215
216 trans.Technology = dmi.TransceiverType_COMBO_GPON_XGSPON
217
218 rxWavelength = []uint32{1490, 1270} // nanometers
219 txWavelength = []uint32{1550, 1577} // nanometers
220 }
221
222 //Create all ports mapped to this transceiver
223 ports := []*dmi.Component{}
224 for _, pon := range trans.Pons {
225 var portProto dmi.PortComponentAttributes_Protocol
226
227 switch pon.Technology {
228 case common.GPON:
229 portProto = dmi.PortComponentAttributes_GPON
230 case common.XGSPON:
231 portProto = dmi.PortComponentAttributes_XGSPON
232 }
233
234 p := dmi.Component{
235 Name: portName,
236 Class: dmi.ComponentType_COMPONENT_TYPE_PORT,
237 Description: "bbsim-pon-port",
238 Uuid: getPonUUID(pon.ID),
239 Parent: trans.Name,
240 Specific: &dmi.Component_PortAttr{
241 PortAttr: &dmi.PortComponentAttributes{
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530242 Protocol: portProto,
243 MappingLabel: fmt.Sprintf("pon-%d", pon.ID),
Elia Battistone8d1fa42022-04-01 10:47:37 +0200244 },
245 },
246 }
247
248 ports = append(ports, &p)
249 }
250
251 transComponent := dmi.Component{
252 Name: trans.Name,
253 Class: dmi.ComponentType_COMPONENT_TYPE_TRANSCEIVER,
254 Description: "bbsim-transceiver",
255 Uuid: &dmi.Uuid{
256 Uuid: trans.Uuid,
257 },
258 Parent: cageName,
259 Specific: &dmi.Component_TransceiverAttr{
260 TransceiverAttr: &dmi.TransceiverComponentsAttributes{
261 FormFactor: dmi.TransceiverComponentsAttributes_SFP_PLUS,
262 TransType: trans.Technology,
263 MaxDistance: 10, // kilometers (see scale below)
264 MaxDistanceScale: dmi.ValueScale_VALUE_SCALE_KILO,
265 RxWavelength: rxWavelength,
266 TxWavelength: txWavelength,
267 WavelengthScale: dmi.ValueScale_VALUE_SCALE_NANO,
268 },
269 },
270 Children: ports,
271 }
272
273 return &transComponent, nil
274}
275
Humera Kousera4442952020-11-23 23:51:19 +0530276func createFanComponent(fanIdx int) *dmi.Component {
277 fanName := fmt.Sprintf("Thermal/Fans/System Fan/%d", fanIdx)
278 fanSerial := fmt.Sprintf("bbsim-fan-serial-%d", fanIdx)
279 return &dmi.Component{
280 Name: fanName,
281 Class: dmi.ComponentType_COMPONENT_TYPE_FAN,
282 Description: "bbsim-fan",
283 Parent: "",
284 ParentRelPos: 0,
285 SerialNum: fanSerial,
286 MfgName: "bbsim-fan",
287 IsFru: false,
288 Uuid: &dmi.Uuid{
289 Uuid: getUUID(fanName),
290 },
291 State: &dmi.ComponentState{},
292 }
293}
294
295func createProcessorComponent(cpuIdx int) *dmi.Component {
296 cpuName := fmt.Sprintf("Systems/1/Processors/%d", cpuIdx)
297 cpuSerial := fmt.Sprintf("bbsim-cpu-serial-%d", cpuIdx)
298 return &dmi.Component{
299 Name: cpuName,
300 Class: dmi.ComponentType_COMPONENT_TYPE_CPU,
301 Description: "bbsim-cpu",
302 Parent: "",
303 ParentRelPos: 0,
304 SerialNum: cpuSerial,
305 MfgName: "bbsim-cpu",
306 IsFru: false,
307 Uuid: &dmi.Uuid{
308 Uuid: getUUID(cpuName),
309 },
310 State: &dmi.ComponentState{},
311 }
312}
313
314func createMemoryComponent(memIdx int) *dmi.Component {
315 memName := fmt.Sprintf("Systems/1/Memory/%d", memIdx)
316 memSerial := fmt.Sprintf("bbsim-ram-serial-%d", memIdx)
317 return &dmi.Component{
318 Name: memName,
319 Class: dmi.ComponentType_COMPONENT_TYPE_MEMORY,
320 Description: "bbsim-ram",
321 Parent: "",
322 ParentRelPos: 0,
323 SerialNum: memSerial,
324 MfgName: "bbsim-ram",
325 IsFru: false,
326 Uuid: &dmi.Uuid{
327 Uuid: getUUID(memName),
328 },
329 State: &dmi.ComponentState{},
330 }
331}
332
333func createDiskComponent(diskIdx int) *dmi.Component {
334 diskName := fmt.Sprintf("Systems/1/Disk/%d", diskIdx)
335 diskSerial := fmt.Sprintf("bbsim-disk-serial-%d", diskIdx)
336 return &dmi.Component{
337 Name: diskName,
338 Class: dmi.ComponentType_COMPONENT_TYPE_STORAGE,
339 Description: "bbsim-disk",
340 Parent: "",
341 ParentRelPos: 0,
342 SerialNum: diskSerial,
343 MfgName: "bbsim-disk",
344 IsFru: false,
345 Uuid: &dmi.Uuid{
346 Uuid: getUUID(diskName),
347 },
348 State: &dmi.ComponentState{},
349 }
350}
351
352func createInnerSurroundingTempComponentSensor(sensorIdx int) *dmi.Component {
353 sensorName := fmt.Sprintf("Systems/1/Sensor/%d", sensorIdx)
354 sensorSerial := fmt.Sprintf("bbsim-sensor-istemp-serial-%d", sensorIdx)
355 return &dmi.Component{
356 Name: sensorName,
357 Class: dmi.ComponentType_COMPONENT_TYPE_SENSOR,
358 Description: "bbsim-istemp",
359 Parent: "",
360 ParentRelPos: 0,
361 SerialNum: sensorSerial,
362 MfgName: "bbsim-istemp",
363 IsFru: false,
364 Uuid: &dmi.Uuid{
365 Uuid: getUUID(sensorName),
366 },
367 State: &dmi.ComponentState{},
368 }
369}
370
hkouser24361d42020-12-14 19:21:47 +0530371func createPowerSupplyComponent(psuIdx int) *dmi.Component {
372 psuName := fmt.Sprintf("Thermal/PSU/SystemPSU/%d", psuIdx)
373 psuSerial := fmt.Sprintf("bbsim-psu-serial-%d", psuIdx)
374 return &dmi.Component{
375 Name: psuName,
376 Class: dmi.ComponentType_COMPONENT_TYPE_POWER_SUPPLY,
377 Description: "bbsim-psu",
378 Parent: "",
379 ParentRelPos: 0,
380 SerialNum: psuSerial,
381 MfgName: "bbsim-psu",
382 IsFru: false,
383 Uuid: &dmi.Uuid{
384 Uuid: getUUID(psuName),
385 },
386 State: &dmi.ComponentState{},
387 }
388}
389
Elia Battistone8d1fa42022-04-01 10:47:37 +0200390func PlugoutTransceiverComponent(transId uint32, dms *DmiAPIServer) error {
391 if dms == nil {
392 return fmt.Errorf("Nil API server")
393 }
394
395 if dms.root == nil {
396 return fmt.Errorf("Device management not started")
397 }
398
399 trans, err := getTransceiverWithId(transId, dms)
400 if err != nil {
401 return err
402 }
403
404 if !trans.PluggedIn {
405 return fmt.Errorf("Cannot plug out transceiver with ID %d since it's not plugged in", transId)
406 }
407
408 //Find the transceiver node in the tree
409 targetUuid := getTransceiverUUID(transId)
410
411 var targetCage *dmi.Component
412 targetTransIndex := -1
413
414loop:
415 for _, rootChild := range dms.root.Children {
416 if rootChild.Uuid.Uuid == getCageUUID(transId).Uuid {
417 currentCage := rootChild
418
419 for j, cageChild := range currentCage.Children {
420 if cageChild.Uuid.Uuid == targetUuid.Uuid {
421 targetCage = currentCage
422 targetTransIndex = j
423 break loop
424 }
425 }
426 }
427 }
428
429 if targetCage == nil || targetTransIndex == -1 {
430 return fmt.Errorf("Cannot find transceiver with id %d", transId)
431 }
432
433 //Remove transceiver
434 targetCage.Children = append(targetCage.Children[:targetTransIndex], targetCage.Children[targetTransIndex+1:]...)
435 logger.WithFields(log.Fields{
436 "transId": transId,
437 "cageName": targetCage.Name,
438 "cageChildren": targetCage.Children,
439 }).Debug("Removed transceiver from DMI inventory")
440
441 //Change plugged-in state
442 trans.PluggedIn = false
443
444 return nil
445}
446
447func PluginTransceiverComponent(transId uint32, dms *DmiAPIServer) error {
448 if dms == nil {
449 return fmt.Errorf("Nil API server")
450 }
451
452 if dms.root == nil {
453 return fmt.Errorf("Device management not started")
454 }
455
456 trans, err := getTransceiverWithId(transId, dms)
457 if err != nil {
458 return err
459 }
460
461 if trans.PluggedIn {
462 return fmt.Errorf("Cannot plug in transceiver with ID %d since it's already plugged in", transId)
463 }
464
465 //Find transceiver node in the tree
466 var targetCage *dmi.Component
467
468 for _, rootChild := range dms.root.Children {
469 if rootChild.Uuid.Uuid == getCageUUID(transId).Uuid {
470 targetCage = rootChild
471 break
472 }
473 }
474
475 if targetCage == nil {
476 return fmt.Errorf("Cannot find cage for transceiver with id %d", transId)
477 }
478
479 //Add transceiver
480 transComponent, err := createTransceiverComponent(trans, targetCage.Name)
481 if err != nil {
482 return err
483 }
484
485 targetCage.Children = append(targetCage.Children, transComponent)
486
487 logger.WithFields(log.Fields{
488 "transId": transId,
489 "cageName": targetCage.Name,
490 "cageChildren": targetCage.Children,
491 }).Debug("Added transceiver to DMI inventory")
492
493 //Change plugged-in state
494 trans.PluggedIn = true
495
496 return nil
497}
498
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530499// StopManagingDevice stops management of a device and cleans up any context and caches for that device
Humera Kouser18b275c2020-11-30 11:30:36 +0530500func (dms *DmiAPIServer) StopManagingDevice(ctx context.Context, req *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
501 logger.Debugf("StopManagingDevice API invoked")
502 if req == nil {
ssiddiqui6ca40702021-03-08 18:20:21 +0530503 return &dmi.StopManagingDeviceResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.StopManagingDeviceResponse_UNDEFINED_REASON}, status.Errorf(codes.FailedPrecondition, "request is empty")
Humera Kouser18b275c2020-11-30 11:30:36 +0530504 }
505
506 if req.Name == "" {
ssiddiqui6ca40702021-03-08 18:20:21 +0530507 return &dmi.StopManagingDeviceResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.StopManagingDeviceResponse_UNKNOWN_DEVICE},
Humera Kouser18b275c2020-11-30 11:30:36 +0530508 status.Errorf(codes.InvalidArgument, "'Name' can not be empty in the request")
509 }
510
511 // Stop the components/go routines created
512 StopMetricGenerator()
513
514 if dms.mPublisherCancelFunc != nil {
515 dms.mPublisherCancelFunc()
516 }
517
Humera Kouser18b275c2020-11-30 11:30:36 +0530518 dms.kafkaEndpoint = ""
519 dms.ipAddress = ""
Elia Battistone8d1fa42022-04-01 10:47:37 +0200520 dms.uuid = nil
Humera Kouser18b275c2020-11-30 11:30:36 +0530521 dms.root = nil
522 dms.metricChannel = nil
523
Elia Battistone8d1fa42022-04-01 10:47:37 +0200524 //Don't clear the Transceivers, so that they will survive
525 //new StartManagingDevice calls
526
Humera Kouser18b275c2020-11-30 11:30:36 +0530527 logger.Infof("Stopped managing the device")
528 return &dmi.StopManagingDeviceResponse{Status: dmi.Status_OK_STATUS}, nil
amit.ghosh258d14c2020-10-02 15:13:38 +0200529}
530
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530531// GetPhysicalInventory gets the HW inventory details of the Device
amit.ghosh258d14c2020-10-02 15:13:38 +0200532func (dms *DmiAPIServer) GetPhysicalInventory(req *dmi.PhysicalInventoryRequest, stream dmi.NativeHWManagementService_GetPhysicalInventoryServer) error {
533 if req == nil || req.DeviceUuid == nil || req.DeviceUuid.Uuid == "" {
534 return status.Errorf(codes.InvalidArgument, "device-UUID missing in the request")
535 }
536
537 // Function to send the response back on the stream
538 sendResponseBackOnStream := func(stream dmi.NativeHWManagementService_GetPhysicalInventoryServer, msg *dmi.PhysicalInventoryResponse) error {
539 err := stream.Send(msg)
540 if err != nil {
541 logger.Errorf("Error sending response to client, error: %v", err)
542 return status.Errorf(codes.Internal, "Error sending response to client "+err.Error())
543 }
544 return nil
545 }
546
Elia Battistone8d1fa42022-04-01 10:47:37 +0200547 if req.DeviceUuid.Uuid != dms.uuid.Uuid {
548 logger.Errorf("Requested uuid =%s, uuid of existing device = %s", req.DeviceUuid.Uuid, dms.uuid.Uuid)
amit.ghosh258d14c2020-10-02 15:13:38 +0200549 // Wrong uuid, return error
550 errResponse := &dmi.PhysicalInventoryResponse{
Humera Kousera4442952020-11-23 23:51:19 +0530551 Status: dmi.Status_ERROR_STATUS,
ssiddiqui6ca40702021-03-08 18:20:21 +0530552 Reason: dmi.PhysicalInventoryResponse_UNKNOWN_DEVICE,
amit.ghosh258d14c2020-10-02 15:13:38 +0200553 Inventory: &dmi.Hardware{},
554 }
555
556 return sendResponseBackOnStream(stream, errResponse)
557 }
558
559 response := &dmi.PhysicalInventoryResponse{
Humera Kousera4442952020-11-23 23:51:19 +0530560 Status: dmi.Status_OK_STATUS,
amit.ghosh258d14c2020-10-02 15:13:38 +0200561 Inventory: &dmi.Hardware{
562 LastChange: &timestamp.Timestamp{
563 Seconds: 0,
564 Nanos: 0,
565 },
Humera Kousera4442952020-11-23 23:51:19 +0530566 Root: dms.root,
amit.ghosh258d14c2020-10-02 15:13:38 +0200567 },
568 }
569 return sendResponseBackOnStream(stream, response)
570}
571
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530572// Contains tells whether arr contains element.
amit.ghosh258d14c2020-10-02 15:13:38 +0200573func Contains(arr []string, element string) bool {
574 for _, item := range arr {
amit.ghosh258d14c2020-10-02 15:13:38 +0200575 if element == item {
576 return true
577 }
578 }
579 return false
580}
581
582func findComponent(l []*dmi.Component, compUUID string) *dmi.Component {
Humera Kousera4442952020-11-23 23:51:19 +0530583 var foundComp *dmi.Component
584
amit.ghosh258d14c2020-10-02 15:13:38 +0200585 for _, comp := range l {
586 logger.Debugf("findComponent slice comp = %v compUUID = %s", comp, compUUID)
587 if comp.Uuid.Uuid == compUUID {
588 return comp
589 }
590
Humera Kousera4442952020-11-23 23:51:19 +0530591 foundComp = findComponent(comp.GetChildren(), compUUID)
592 if foundComp != nil {
593 return foundComp
amit.ghosh258d14c2020-10-02 15:13:38 +0200594 }
595 }
596
597 return nil
598}
599
Humera Kousera4442952020-11-23 23:51:19 +0530600func findComponentsOfType(l []*dmi.Component, compType dmi.ComponentType) []*dmi.Component {
601 var comps []*dmi.Component
602 findComponents(l, compType, &comps)
603 return comps
604}
605
606func findComponents(l []*dmi.Component, compType dmi.ComponentType, collector *[]*dmi.Component) {
607
608 for _, comp := range l {
609 if comp.Class == compType {
610 *collector = append(*collector, comp)
611 //logger.Debugf("Added collector = %v", *collector)
612 }
613
614 findComponents(comp.GetChildren(), compType, collector)
615 }
616}
617
amit.ghosh258d14c2020-10-02 15:13:38 +0200618func sendGetHWComponentResponse(c *dmi.Component, stream dmi.NativeHWManagementService_GetHWComponentInfoServer) error {
Humera Kousera4442952020-11-23 23:51:19 +0530619 apiStatus := dmi.Status_OK_STATUS
ssiddiqui6ca40702021-03-08 18:20:21 +0530620 reason := dmi.HWComponentInfoGetResponse_UNDEFINED_REASON
amit.ghosh258d14c2020-10-02 15:13:38 +0200621
622 if c == nil {
Humera Kousera4442952020-11-23 23:51:19 +0530623 apiStatus = dmi.Status_ERROR_STATUS
ssiddiqui6ca40702021-03-08 18:20:21 +0530624 reason = dmi.HWComponentInfoGetResponse_UNKNOWN_DEVICE
amit.ghosh258d14c2020-10-02 15:13:38 +0200625 }
626
627 response := &dmi.HWComponentInfoGetResponse{
628 Status: apiStatus,
629 Reason: reason,
630 Component: c,
631 }
632
633 err := stream.Send(response)
634 if err != nil {
635 logger.Errorf("Error sending response to client, error: %v", err)
636 return status.Errorf(codes.Internal, "Error sending response to client "+err.Error())
637 }
638 return nil
639}
640
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530641// GetHWComponentInfo gets the details of a particular HW component
amit.ghosh258d14c2020-10-02 15:13:38 +0200642func (dms *DmiAPIServer) GetHWComponentInfo(req *dmi.HWComponentInfoGetRequest, stream dmi.NativeHWManagementService_GetHWComponentInfoServer) error {
643 logger.Debugf("GetHWComponentInfo() invoked with request %+v", req)
644
645 if req == nil {
646 return status.Errorf(codes.FailedPrecondition, "can not entertain nil request")
647 }
648 if stream == nil {
649 logger.Errorf("stream to send is nil, not sending response from gRPC server ")
650 return status.Errorf(codes.Internal, "stream to send is nil, can not send response from gRPC server")
651 }
652
Humera Kouser18b275c2020-11-30 11:30:36 +0530653 //if component list is empty, return error
654 if dms.root == nil {
655 logger.Errorf("Error occurred, device is not managed")
656 return status.Errorf(codes.Internal, "Error occurred, device is not managed, please start managing device")
657 }
amit.ghosh258d14c2020-10-02 15:13:38 +0200658 // Search for the component and return it
Humera Kousera4442952020-11-23 23:51:19 +0530659 c := findComponent(dms.root.Children, req.ComponentUuid.Uuid)
660
amit.ghosh258d14c2020-10-02 15:13:38 +0200661 return sendGetHWComponentResponse(c, stream)
662}
663
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530664// SetHWComponentInfo sets the permissible attributes of a HW component
amit.ghosh258d14c2020-10-02 15:13:38 +0200665func (dms *DmiAPIServer) SetHWComponentInfo(context.Context, *dmi.HWComponentInfoSetRequest) (*dmi.HWComponentInfoSetResponse, error) {
666 return nil, status.Errorf(codes.Unimplemented, "rpc SetHWComponentInfo not implemented")
667}
668
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530669// SetLoggingEndpoint sets the location to which logs need to be shipped
ssiddiqui6ca40702021-03-08 18:20:21 +0530670func (dms *DmiAPIServer) SetLoggingEndpoint(_ context.Context, request *dmi.SetLoggingEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
671 logger.Debugf("SetLoggingEndpoint called with request %+v", request)
672 errRetFunc := func(stat dmi.Status, reason dmi.SetRemoteEndpointResponse_Reason) (*dmi.SetRemoteEndpointResponse, error) {
673 return &dmi.SetRemoteEndpointResponse{
674 Status: stat,
675 Reason: reason,
676 }, status.Errorf(codes.InvalidArgument, "invalid request")
677 }
678
679 //check the validity of the request
680 if request == nil {
681 return errRetFunc(dmi.Status_ERROR_STATUS, dmi.SetRemoteEndpointResponse_UNKNOWN_DEVICE)
682 }
683 if request.LoggingEndpoint == "" {
684 return errRetFunc(dmi.Status_ERROR_STATUS, dmi.SetRemoteEndpointResponse_LOGGING_ENDPOINT_ERROR)
685 }
686 if request.LoggingProtocol == "" {
687 return errRetFunc(dmi.Status_ERROR_STATUS, dmi.SetRemoteEndpointResponse_LOGGING_ENDPOINT_PROTOCOL_ERROR)
688 }
Elia Battistone8d1fa42022-04-01 10:47:37 +0200689 if request.DeviceUuid == nil || request.DeviceUuid.Uuid != dms.uuid.Uuid {
ssiddiqui6ca40702021-03-08 18:20:21 +0530690 return errRetFunc(dmi.Status_ERROR_STATUS, dmi.SetRemoteEndpointResponse_UNKNOWN_DEVICE)
691 }
692
693 dms.loggingEndpoint = request.LoggingEndpoint
694 dms.loggingProtocol = request.LoggingProtocol
695
696 return &dmi.SetRemoteEndpointResponse{
697 Status: dmi.Status_OK_STATUS,
698 }, nil
amit.ghosh258d14c2020-10-02 15:13:38 +0200699}
700
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530701// GetLoggingEndpoint gets the configured location to which the logs are being shipped
ssiddiqui6ca40702021-03-08 18:20:21 +0530702func (dms *DmiAPIServer) GetLoggingEndpoint(_ context.Context, request *dmi.HardwareID) (*dmi.GetLoggingEndpointResponse, error) {
703 logger.Debugf("GetLoggingEndpoint called with request %+v", request)
704 if request == nil || request.Uuid == nil || request.Uuid.Uuid == "" {
705 return &dmi.GetLoggingEndpointResponse{
706 Status: dmi.Status_ERROR_STATUS,
707 Reason: dmi.GetLoggingEndpointResponse_UNKNOWN_DEVICE,
708 }, status.Errorf(codes.InvalidArgument, "invalid request")
709 }
Elia Battistone8d1fa42022-04-01 10:47:37 +0200710 if request.Uuid.Uuid != dms.uuid.Uuid {
ssiddiqui6ca40702021-03-08 18:20:21 +0530711 return &dmi.GetLoggingEndpointResponse{
712 Status: dmi.Status_ERROR_STATUS,
713 Reason: dmi.GetLoggingEndpointResponse_UNKNOWN_DEVICE,
714 }, nil
715 }
716
717 return &dmi.GetLoggingEndpointResponse{
718 Status: dmi.Status_OK_STATUS,
719 LoggingEndpoint: dms.loggingEndpoint,
720 LoggingProtocol: dms.loggingProtocol,
721 }, nil
amit.ghosh258d14c2020-10-02 15:13:38 +0200722}
723
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530724// SetMsgBusEndpoint sets the location of the Message Bus to which events and metrics are shipped
Humera Kousera4442952020-11-23 23:51:19 +0530725func (dms *DmiAPIServer) SetMsgBusEndpoint(ctx context.Context, request *dmi.SetMsgBusEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
726 logger.Debugf("SetMsgBusEndpoint() invoked with request: %+v and context: %v", request, ctx)
727 if request == nil || request.MsgbusEndpoint == "" {
ssiddiqui6ca40702021-03-08 18:20:21 +0530728 return &dmi.SetRemoteEndpointResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.SetRemoteEndpointResponse_MSGBUS_ENDPOINT_ERROR},
Humera Kousera4442952020-11-23 23:51:19 +0530729 status.Errorf(codes.FailedPrecondition, "request is nil")
730 }
731 olt := devices.GetOLT()
732 dms.kafkaEndpoint = request.MsgbusEndpoint
733
734 // close the old publisher
735 if dms.mPublisherCancelFunc != nil {
736 dms.mPublisherCancelFunc()
737 }
738
739 // initialize a new publisher
740 var nCtx context.Context
741 nCtx, dms.mPublisherCancelFunc = context.WithCancel(context.Background())
742 // initialize a publisher
743 if err := InitializeDMKafkaPublishers(sarama.NewAsyncProducer, olt.ID, dms.kafkaEndpoint); err == nil {
hkouser24361d42020-12-14 19:21:47 +0530744 // start a go routine which will read from channel and publish on kafka topic dm.metrics
Humera Kousera4442952020-11-23 23:51:19 +0530745 go DMKafkaPublisher(nCtx, dms.metricChannel, "dm.metrics")
hkouser24361d42020-12-14 19:21:47 +0530746 // start a go routine which will read from channel and publish on kafka topic dm.events
747 go DMKafkaPublisher(nCtx, dms.eventChannel, "dm.events")
Humera Kousera4442952020-11-23 23:51:19 +0530748 } else {
hkouser24361d42020-12-14 19:21:47 +0530749 logger.Errorf("Failed to start metric kafka publisher: %v", err)
ssiddiqui6ca40702021-03-08 18:20:21 +0530750 return &dmi.SetRemoteEndpointResponse{Status: dmi.Status_ERROR_STATUS, Reason: dmi.SetRemoteEndpointResponse_MSGBUS_ENDPOINT_ERROR}, err
Humera Kousera4442952020-11-23 23:51:19 +0530751 }
752
ssiddiqui6ca40702021-03-08 18:20:21 +0530753 return &dmi.SetRemoteEndpointResponse{Status: dmi.Status_OK_STATUS, Reason: dmi.SetRemoteEndpointResponse_UNDEFINED_REASON}, nil
amit.ghosh258d14c2020-10-02 15:13:38 +0200754}
755
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530756// GetMsgBusEndpoint gets the configured location to which the events and metrics are being shipped
amit.ghosh258d14c2020-10-02 15:13:38 +0200757func (dms *DmiAPIServer) GetMsgBusEndpoint(context.Context, *empty.Empty) (*dmi.GetMsgBusEndpointResponse, error) {
Humera Kousera4442952020-11-23 23:51:19 +0530758 logger.Debugf("GetMsgBusEndpoint() invoked")
759 if dms.kafkaEndpoint != "" {
760 return &dmi.GetMsgBusEndpointResponse{
761 Status: dmi.Status_OK_STATUS,
ssiddiqui6ca40702021-03-08 18:20:21 +0530762 Reason: dmi.GetMsgBusEndpointResponse_UNDEFINED_REASON,
Humera Kousera4442952020-11-23 23:51:19 +0530763 MsgbusEndpoint: dms.kafkaEndpoint,
764 }, nil
765 }
766 return &dmi.GetMsgBusEndpointResponse{
767 Status: dmi.Status_ERROR_STATUS,
ssiddiqui6ca40702021-03-08 18:20:21 +0530768 Reason: dmi.GetMsgBusEndpointResponse_INTERNAL_ERROR,
Humera Kousera4442952020-11-23 23:51:19 +0530769 MsgbusEndpoint: "",
770 }, nil
amit.ghosh258d14c2020-10-02 15:13:38 +0200771}
772
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530773// GetManagedDevices returns an object containing a list of devices managed by this entity
amit.ghosh258d14c2020-10-02 15:13:38 +0200774func (dms *DmiAPIServer) GetManagedDevices(context.Context, *empty.Empty) (*dmi.ManagedDevicesResponse, error) {
775 retResponse := dmi.ManagedDevicesResponse{}
776 //If our uuid is empty, we return empty list; else we fill details and return
Elia Battistone8d1fa42022-04-01 10:47:37 +0200777 if dms.root != nil {
Hardik Windlass63e35cf2022-02-03 05:58:09 +0000778 root := dmi.ManagedDeviceInfo{
779 Info: &dmi.ModifiableComponent{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200780 Name: getOltName(),
Hardik Windlass63e35cf2022-02-03 05:58:09 +0000781 Uri: &dmi.Uri{
782 Uri: dms.ipAddress,
783 },
784 },
Elia Battistone8d1fa42022-04-01 10:47:37 +0200785 DeviceUuid: dms.uuid,
amit.ghosh258d14c2020-10-02 15:13:38 +0200786 }
787
788 retResponse.Devices = append(retResponse.Devices, &root)
789 }
Hardik Windlassa738f902022-02-11 07:50:38 +0000790 retResponse.Status = dmi.Status_OK_STATUS
amit.ghosh258d14c2020-10-02 15:13:38 +0200791
792 return &retResponse, nil
793}
Humera Kousera4442952020-11-23 23:51:19 +0530794
Abhay Kumarc5723cc2023-06-08 12:09:30 +0530795// GetLogLevel Gets the configured log level for a certain entity on a certain device.
Humera Kousera4442952020-11-23 23:51:19 +0530796func (dms *DmiAPIServer) GetLogLevel(context.Context, *dmi.GetLogLevelRequest) (*dmi.GetLogLevelResponse, error) {
797 return &dmi.GetLogLevelResponse{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200798 Status: dmi.Status_OK_STATUS,
799 DeviceUuid: dms.uuid,
800 LogLevels: []*dmi.EntitiesLogLevel{},
Humera Kousera4442952020-11-23 23:51:19 +0530801 }, nil
802}
803
804// SetLogLevel Sets the log level of the device, for each given entity to a certain level.
805func (dms *DmiAPIServer) SetLogLevel(context.Context, *dmi.SetLogLevelRequest) (*dmi.SetLogLevelResponse, error) {
806 return &dmi.SetLogLevelResponse{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200807 Status: dmi.Status_OK_STATUS,
808 DeviceUuid: dms.uuid,
Humera Kousera4442952020-11-23 23:51:19 +0530809 }, nil
810}
811
812// GetLoggableEntities Gets the entities of a device on which log can be configured.
813func (dms *DmiAPIServer) GetLoggableEntities(context.Context, *dmi.GetLoggableEntitiesRequest) (*dmi.GetLogLevelResponse, error) {
814 return &dmi.GetLogLevelResponse{
Elia Battistone8d1fa42022-04-01 10:47:37 +0200815 Status: dmi.Status_OK_STATUS,
816 DeviceUuid: dms.uuid,
817 LogLevels: []*dmi.EntitiesLogLevel{},
Humera Kousera4442952020-11-23 23:51:19 +0530818 }, nil
819}
Hardik Windlass63e35cf2022-02-03 05:58:09 +0000820
821// Performs the heartbeat check
822func (dms *DmiAPIServer) HeartbeatCheck(context.Context, *empty.Empty) (*dmi.Heartbeat, error) {
823 return nil, status.Errorf(codes.Unimplemented, "rpc HeartbeatCheck not implemented")
824}
825
826// Performs the reboot of the device
827func (dms *DmiAPIServer) RebootDevice(context.Context, *dmi.RebootDeviceRequest) (*dmi.RebootDeviceResponse, error) {
828 return nil, status.Errorf(codes.Unimplemented, "rpc RebootDevice not implemented")
829}