blob: edefc54db79308acba1b1f09bf7caac54cff4d83 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001/*
2 * Copyright 2021-present Open Networking Foundation
3
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 */
16package device
17
18import (
19 "context"
20 "errors"
21
22 "github.com/golang/protobuf/ptypes/empty"
23 "github.com/opencord/voltha-go/rw_core/utils"
24 "github.com/opencord/voltha-lib-go/v7/pkg/log"
25 "github.com/opencord/voltha-protos/v5/go/common"
khenaidoo9beaaf12021-10-19 17:32:01 -040026 "github.com/opencord/voltha-protos/v5/go/extension"
27 "github.com/opencord/voltha-protos/v5/go/omci"
khenaidood948f772021-08-11 17:49:24 -040028 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
29 "github.com/opencord/voltha-protos/v5/go/voltha"
30 "google.golang.org/grpc/codes"
31 "google.golang.org/grpc/status"
32)
33
34// CreateDevice creates a new parent device in the data model
35func (dMgr *Manager) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
36 if device.MacAddress == "" && device.GetHostAndPort() == "" {
37 logger.Errorf(ctx, "no-device-info-present")
38 return &voltha.Device{}, errors.New("no-device-info-present; MAC or HOSTIP&PORT")
39 }
40 ctx = utils.WithRPCMetadataContext(ctx, "CreateDevice")
41 logger.Debugw(ctx, "create-device", log.Fields{"device": *device})
42
43 deviceExist, err := dMgr.isParentDeviceExist(ctx, device)
44 if err != nil {
45 logger.Errorf(ctx, "failed-to-fetch-parent-device-info")
46 return nil, err
47 }
48 if deviceExist {
49 logger.Errorf(ctx, "device-is-pre-provisioned-already-with-same-ip-port-or-mac-address")
50 return nil, errors.New("device is already pre-provisioned")
51 }
52 logger.Debugw(ctx, "create-device", log.Fields{"device": device})
53
54 // Ensure this device is set as root
55 device.Root = true
56 // Create and start a device agent for that device
Himani Chawla4b4bd252021-11-08 15:59:40 +053057 agent := newAgent(device, dMgr, dMgr.dbPath, dMgr.dProxy, dMgr.internalTimeout, dMgr.rpcTimeout, dMgr.flowTimeout)
khenaidood948f772021-08-11 17:49:24 -040058 device, err = agent.start(ctx, false, device)
59 if err != nil {
60 logger.Errorw(ctx, "fail-to-start-device", log.Fields{"device-id": agent.deviceID, "error": err})
61 return nil, err
62 }
63 dMgr.addDeviceAgentToMap(agent)
64 return device, nil
65}
66
67// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
68func (dMgr *Manager) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
69 ctx = utils.WithRPCMetadataContext(ctx, "EnableDevice")
70 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
71
72 logger.Debugw(ctx, "enable-device", log.Fields{"device-id": id.Id})
73 agent := dMgr.getDeviceAgent(ctx, id.Id)
74 if agent == nil {
75 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
76 }
77 return &empty.Empty{}, agent.enableDevice(ctx)
78}
79
80// DisableDevice disables a device along with any child device it may have
81func (dMgr *Manager) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
82 ctx = utils.WithRPCMetadataContext(ctx, "DisableDevice")
83 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
84
85 logger.Debugw(ctx, "disable-device", log.Fields{"device-id": id.Id})
86 agent := dMgr.getDeviceAgent(ctx, id.Id)
87 if agent == nil {
88 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
89 }
90 return &empty.Empty{}, agent.disableDevice(ctx)
91}
92
93//RebootDevice invoked the reboot API to the corresponding adapter
94func (dMgr *Manager) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
95 ctx = utils.WithRPCMetadataContext(ctx, "RebootDevice")
96 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
97
98 logger.Debugw(ctx, "reboot-device", log.Fields{"device-id": id.Id})
99 agent := dMgr.getDeviceAgent(ctx, id.Id)
100 if agent == nil {
101 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
102 }
103 return &empty.Empty{}, agent.rebootDevice(ctx)
104}
105
106// DeleteDevice removes a device from the data model
107func (dMgr *Manager) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
108 ctx = utils.WithRPCMetadataContext(ctx, "DeleteDevice")
109 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
110
111 logger.Debugw(ctx, "delete-device", log.Fields{"device-id": id.Id})
112 agent := dMgr.getDeviceAgent(ctx, id.Id)
113 if agent == nil {
114 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
115 }
116 return &empty.Empty{}, agent.deleteDevice(ctx)
117}
118
119// ForceDeleteDevice removes a device from the data model forcefully without successfully waiting for the adapters.
120func (dMgr *Manager) ForceDeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
121 ctx = utils.WithRPCMetadataContext(ctx, "ForceDeleteDevice")
122 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
123
124 logger.Debugw(ctx, "force-delete-device", log.Fields{"device-id": id.Id})
125 agent := dMgr.getDeviceAgent(ctx, id.Id)
126 if agent == nil {
127 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
128 }
129 return &empty.Empty{}, agent.deleteDeviceForce(ctx)
130}
131
132// ListDevices retrieves the latest devices from the data model
133func (dMgr *Manager) ListDevices(ctx context.Context, _ *empty.Empty) (*voltha.Devices, error) {
134 ctx = utils.WithRPCMetadataContext(ctx, "ListDevices")
135
136 logger.Debug(ctx, "list-devices")
137 result := &voltha.Devices{}
138
139 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
140 result.Items = append(result.Items, value.(*Agent).device)
141 return true
142 })
143
144 logger.Debugw(ctx, "list-devices-end", log.Fields{"len": len(result.Items)})
145 return result, nil
146}
147
148// ListDeviceIds retrieves the latest device IDs information from the data model (memory data only)
149func (dMgr *Manager) ListDeviceIds(ctx context.Context, _ *empty.Empty) (*voltha.IDs, error) {
150 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceIds")
151
152 logger.Debug(ctx, "list-device-ids")
153 // Report only device IDs that are in the device agent map
154 return dMgr.listDeviceIdsFromMap(), nil
155}
156
157// ReconcileDevices is a request to a voltha core to update its list of managed devices. This will
158// trigger loading the devices along with their children and parent in memory
159func (dMgr *Manager) ReconcileDevices(ctx context.Context, ids *voltha.IDs) (*empty.Empty, error) {
160 ctx = utils.WithRPCMetadataContext(ctx, "ReconcileDevices")
161
162 numDevices := 0
163 if ids != nil {
164 numDevices = len(ids.Items)
165 }
166
167 logger.Debugw(ctx, "reconcile-devices", log.Fields{"num-devices": numDevices})
168 if ids != nil && len(ids.Items) != 0 {
169 toReconcile := len(ids.Items)
170 reconciled := 0
171 var err error
172 for _, id := range ids.Items {
173 if err = dMgr.load(ctx, id.Id); err != nil {
174 logger.Warnw(ctx, "failure-reconciling-device", log.Fields{"device-id": id.Id, "error": err})
175 } else {
176 reconciled++
177 }
178 }
179 if toReconcile != reconciled {
180 return nil, status.Errorf(codes.DataLoss, "less-device-reconciled-than-requested:%d/%d", reconciled, toReconcile)
181 }
182 } else {
183 return nil, status.Errorf(codes.InvalidArgument, "empty-list-of-ids")
184 }
185 return &empty.Empty{}, nil
186}
187
188// GetDevice exists primarily to implement the gRPC interface.
189// Internal functions should call getDeviceReadOnly instead.
190func (dMgr *Manager) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
191 ctx = utils.WithRPCMetadataContext(ctx, "GetDevice")
192 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
193
194 return dMgr.getDeviceReadOnly(ctx, id.Id)
195}
196
197// convenience to avoid redefining
198var operationFailureResp = &common.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}
199
200// DownloadImage execute an image download request
201func (dMgr *Manager) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
202 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImage")
203 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
204
205 logger.Debugw(ctx, "download-image", log.Fields{"device-id": img.Id, "image-name": img.Name})
206 agent := dMgr.getDeviceAgent(ctx, img.Id)
207 if agent == nil {
208 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
209 }
210 resp, err := agent.downloadImage(ctx, img)
211 if err != nil {
212 return operationFailureResp, err
213 }
214 return resp, nil
215}
216
217// CancelImageDownload cancels image download request
218func (dMgr *Manager) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
219 ctx = utils.WithRPCMetadataContext(ctx, "CancelImageDownload")
220 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
221
222 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
223 agent := dMgr.getDeviceAgent(ctx, img.Id)
224 if agent == nil {
225 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
226 }
227 resp, err := agent.cancelImageDownload(ctx, img)
228 if err != nil {
229 return operationFailureResp, err
230 }
231 return resp, nil
232}
233
234// ActivateImageUpdate activates image update request
235func (dMgr *Manager) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
236 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImageUpdate")
237 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
238
239 logger.Debugw(ctx, "activate-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
240 agent := dMgr.getDeviceAgent(ctx, img.Id)
241 if agent == nil {
242 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
243 }
244 resp, err := agent.activateImage(ctx, img)
245 if err != nil {
246 return operationFailureResp, err
247 }
248 return resp, nil
249}
250
251// RevertImageUpdate reverts image update
252func (dMgr *Manager) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
253 ctx = utils.WithRPCMetadataContext(ctx, "RevertImageUpdate")
254 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
255
256 logger.Debugw(ctx, "rever-image-update", log.Fields{"device-id": img.Id, "image-name": img.Name})
257 agent := dMgr.getDeviceAgent(ctx, img.Id)
258 if agent == nil {
259 return operationFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
260 }
261 resp, err := agent.revertImage(ctx, img)
262 if err != nil {
263 return operationFailureResp, err
264 }
265 return resp, nil
266}
267
268func (dMgr *Manager) DownloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
269 if err := dMgr.validateImageDownloadRequest(request); err != nil {
270 return nil, err
271 }
272
273 ctx = utils.WithRPCMetadataContext(ctx, "DownloadImageToDevice")
274 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
275
276 for index, deviceID := range request.DeviceId {
277 // Create download request per device
278 downloadReq := &voltha.DeviceImageDownloadRequest{
279 Image: request.Image,
280 ActivateOnSuccess: request.ActivateOnSuccess,
281 CommitOnSuccess: request.CommitOnSuccess,
282 }
283
284 //slice-out only single deviceID from the request
285 downloadReq.DeviceId = request.DeviceId[index : index+1]
286
287 go func(deviceID string, req *voltha.DeviceImageDownloadRequest, ch chan []*voltha.DeviceImageState) {
288 agent := dMgr.getDeviceAgent(ctx, deviceID)
289 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530290 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
291 ch <- []*voltha.DeviceImageState{{
292 DeviceId: deviceID,
293 ImageState: &voltha.ImageState{
294 Version: req.GetImage().GetVersion(),
295 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
296 Reason: voltha.ImageState_UNKNOWN_ERROR,
297 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
298 },
299 }}
khenaidood948f772021-08-11 17:49:24 -0400300 return
301 }
302
303 resp, err := agent.downloadImageToDevice(ctx, req)
304 if err != nil {
305 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530306 ch <- []*voltha.DeviceImageState{{
307 DeviceId: deviceID,
308 ImageState: &voltha.ImageState{
309 Version: req.GetImage().GetVersion(),
310 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
311 Reason: voltha.ImageState_UNKNOWN_ERROR,
312 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
313 },
314 }}
khenaidood948f772021-08-11 17:49:24 -0400315 return
316 }
317
318 err = dMgr.validateDeviceImageResponse(resp)
319 if err != nil {
320 logger.Errorw(ctx, "download-image-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530321 ch <- []*voltha.DeviceImageState{{
322 DeviceId: deviceID,
323 ImageState: &voltha.ImageState{
324 Version: req.GetImage().GetVersion(),
325 DownloadState: voltha.ImageState_DOWNLOAD_FAILED,
326 Reason: voltha.ImageState_UNKNOWN_ERROR,
327 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
328 },
329 }}
khenaidood948f772021-08-11 17:49:24 -0400330 return
331 }
332 ch <- resp.GetDeviceImageStates()
333 }(deviceID.GetId(), downloadReq, respCh)
334
335 }
336
337 return dMgr.waitForAllResponses(ctx, "download-image-to-device", respCh, len(request.GetDeviceId()))
338}
339
340func (dMgr *Manager) GetImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
341 if err := dMgr.validateImageRequest(request); err != nil {
342 return nil, err
343 }
344
345 ctx = utils.WithRPCMetadataContext(ctx, "GetImageStatus")
346
347 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
348 for index, deviceID := range request.DeviceId {
349 // Create status request per device
350 imageStatusReq := &voltha.DeviceImageRequest{
351 Version: request.Version,
352 CommitOnSuccess: request.CommitOnSuccess,
353 }
354
355 //slice-out only single deviceID from the request
356 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
357
358 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
359 agent := dMgr.getDeviceAgent(ctx, deviceID)
360 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530361 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
362 ch <- []*voltha.DeviceImageState{{
363 DeviceId: deviceID,
364 ImageState: &voltha.ImageState{
365 Version: request.GetVersion(),
366 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
367 Reason: voltha.ImageState_UNKNOWN_ERROR,
368 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
369 },
370 }}
khenaidood948f772021-08-11 17:49:24 -0400371 return
372 }
373
374 resp, err := agent.getImageStatus(ctx, req)
375 if err != nil {
376 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530377 ch <- []*voltha.DeviceImageState{{
378 DeviceId: deviceID,
379 ImageState: &voltha.ImageState{
380 Version: request.GetVersion(),
381 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
382 Reason: voltha.ImageState_UNKNOWN_ERROR,
383 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
384 },
385 }}
khenaidood948f772021-08-11 17:49:24 -0400386 return
387 }
388
389 err = dMgr.validateDeviceImageResponse(resp)
390 if err != nil {
391 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530392 ch <- []*voltha.DeviceImageState{{
393 DeviceId: deviceID,
394 ImageState: &voltha.ImageState{
395 Version: request.GetVersion(),
396 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
397 Reason: voltha.ImageState_UNKNOWN_ERROR,
398 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
399 },
400 }}
khenaidood948f772021-08-11 17:49:24 -0400401 return
402 }
403 ch <- resp.GetDeviceImageStates()
404 }(deviceID.GetId(), imageStatusReq, respCh)
405
406 }
407
408 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
409}
410
411func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
412 if err := dMgr.validateImageRequest(request); err != nil {
413 return nil, err
414 }
415
416 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
417 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
418
419 for index, deviceID := range request.DeviceId {
420 // Create abort request per device
421 abortImageReq := &voltha.DeviceImageRequest{
422 Version: request.Version,
423 CommitOnSuccess: request.CommitOnSuccess,
424 }
425
426 //slice-out only single deviceID from the request
427 abortImageReq.DeviceId = request.DeviceId[index : index+1]
428
429 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
430 agent := dMgr.getDeviceAgent(ctx, deviceID)
431 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530432 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
433 ch <- []*voltha.DeviceImageState{{
434 DeviceId: deviceID,
435 ImageState: &voltha.ImageState{
436 Version: request.GetVersion(),
437 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
438 Reason: voltha.ImageState_UNKNOWN_ERROR,
439 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
440 },
441 }}
khenaidood948f772021-08-11 17:49:24 -0400442 return
443 }
444
445 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
446 if err != nil {
447 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530448 ch <- []*voltha.DeviceImageState{{
449 DeviceId: deviceID,
450 ImageState: &voltha.ImageState{
451 Version: request.GetVersion(),
452 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
453 Reason: voltha.ImageState_UNKNOWN_ERROR,
454 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
455 },
456 }}
khenaidood948f772021-08-11 17:49:24 -0400457 return
458 }
459
460 err = dMgr.validateDeviceImageResponse(resp)
461 if err != nil {
462 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530463 ch <- []*voltha.DeviceImageState{{
464 DeviceId: deviceID,
465 ImageState: &voltha.ImageState{
466 Version: request.GetVersion(),
467 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
468 Reason: voltha.ImageState_UNKNOWN_ERROR,
469 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
470 },
471 }}
khenaidood948f772021-08-11 17:49:24 -0400472 return
473 }
474 ch <- resp.GetDeviceImageStates()
475 }(deviceID.GetId(), abortImageReq, respCh)
476
477 }
478
479 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
480}
481
482func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
483 if id == nil || id.Id == "" {
484 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
485 }
486
487 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
488 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
489 agent := dMgr.getDeviceAgent(ctx, id.Id)
490 if agent == nil {
491 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
492 }
493
494 resp, err := agent.getOnuImages(ctx, id)
495 if err != nil {
496 return nil, err
497 }
498
499 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
500
501 return resp, nil
502}
503
504func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
505 if err := dMgr.validateImageRequest(request); err != nil {
506 return nil, err
507 }
508
509 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
510 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
511
512 for index, deviceID := range request.DeviceId {
513 // Create activate request per device
514 activateImageReq := &voltha.DeviceImageRequest{
515 Version: request.Version,
516 CommitOnSuccess: request.CommitOnSuccess,
517 }
518
519 //slice-out only single deviceID from the request
520 activateImageReq.DeviceId = request.DeviceId[index : index+1]
521
522 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
523 agent := dMgr.getDeviceAgent(ctx, deviceID)
524 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530525 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
526 ch <- []*voltha.DeviceImageState{{
527 DeviceId: deviceID,
528 ImageState: &voltha.ImageState{
529 Version: request.GetVersion(),
530 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
531 Reason: voltha.ImageState_UNKNOWN_ERROR,
532 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
533 },
534 }}
khenaidood948f772021-08-11 17:49:24 -0400535 return
536 }
537
538 resp, err := agent.activateImageOnDevice(ctx, req)
539 if err != nil {
540 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530541 ch <- []*voltha.DeviceImageState{{
542 DeviceId: deviceID,
543 ImageState: &voltha.ImageState{
544 Version: request.GetVersion(),
545 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
546 Reason: voltha.ImageState_UNKNOWN_ERROR,
547 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
548 },
549 }}
khenaidood948f772021-08-11 17:49:24 -0400550 return
551 }
552
553 err = dMgr.validateDeviceImageResponse(resp)
554 if err != nil {
555 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530556 ch <- []*voltha.DeviceImageState{{
557 DeviceId: deviceID,
558 ImageState: &voltha.ImageState{
559 Version: request.GetVersion(),
560 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
561 Reason: voltha.ImageState_UNKNOWN_ERROR,
562 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
563 },
564 }}
khenaidood948f772021-08-11 17:49:24 -0400565 return
566 }
567
568 ch <- resp.GetDeviceImageStates()
569 }(deviceID.GetId(), activateImageReq, respCh)
570
571 }
572
573 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
574}
575
576func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
577 if err := dMgr.validateImageRequest(request); err != nil {
578 return nil, err
579 }
580
581 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
582 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
583
584 for index, deviceID := range request.DeviceId {
585 // Create commit request per device
586 commitImageReq := &voltha.DeviceImageRequest{
587 Version: request.Version,
588 CommitOnSuccess: request.CommitOnSuccess,
589 }
590 //slice-out only single deviceID from the request
591 commitImageReq.DeviceId = request.DeviceId[index : index+1]
592
593 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
594 agent := dMgr.getDeviceAgent(ctx, deviceID)
595 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530596 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
597 ch <- []*voltha.DeviceImageState{{
598 DeviceId: deviceID,
599 ImageState: &voltha.ImageState{
600 Version: request.GetVersion(),
601 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
602 Reason: voltha.ImageState_UNKNOWN_ERROR,
603 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
604 },
605 }}
khenaidood948f772021-08-11 17:49:24 -0400606 return
607 }
608
609 resp, err := agent.commitImage(ctx, req)
610 if err != nil {
611 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530612 ch <- []*voltha.DeviceImageState{{
613 DeviceId: deviceID,
614 ImageState: &voltha.ImageState{
615 Version: request.GetVersion(),
616 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
617 Reason: voltha.ImageState_UNKNOWN_ERROR,
618 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
619 },
620 }}
khenaidood948f772021-08-11 17:49:24 -0400621 return
622 }
623
624 err = dMgr.validateDeviceImageResponse(resp)
625 if err != nil {
626 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530627 ch <- []*voltha.DeviceImageState{{
628 DeviceId: deviceID,
629 ImageState: &voltha.ImageState{
630 Version: request.GetVersion(),
631 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
632 Reason: voltha.ImageState_UNKNOWN_ERROR,
633 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
634 },
635 }}
khenaidood948f772021-08-11 17:49:24 -0400636 return
637 }
638 ch <- resp.GetDeviceImageStates()
639 }(deviceID.GetId(), commitImageReq, respCh)
640
641 }
642
643 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
644}
645
646// convenience to avoid redefining
647var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
648
649// GetImageDownloadStatus returns status of image download
650func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
651 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
652 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
653
654 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
655 agent := dMgr.getDeviceAgent(ctx, img.Id)
656 if agent == nil {
657 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
658 }
659 resp, err := agent.getImageDownloadStatus(ctx, img)
660 if err != nil {
661 return imageDownloadFailureResp, err
662 }
663 return resp, nil
664}
665
666// GetImageDownload returns image download
667func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
668 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
669 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
670
671 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
672 agent := dMgr.getDeviceAgent(ctx, img.Id)
673 if agent == nil {
674 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
675 }
676 resp, err := agent.getImageDownload(ctx, img)
677 if err != nil {
678 return imageDownloadFailureResp, err
679 }
680 return resp, nil
681}
682
683// ListImageDownloads returns image downloads
684func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
685 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
686 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
687
688 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
689 agent := dMgr.getDeviceAgent(ctx, id.Id)
690 if agent == nil {
691 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
692 }
693 resp, err := agent.listImageDownloads(ctx, id.Id)
694 if err != nil {
695 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
696 }
697 return resp, nil
698}
699
700// GetImages returns all images for a specific device entry
701func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
702 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
703 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
704
705 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
706 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
707 if err != nil {
708 return nil, err
709 }
710 return device.Images, nil
711}
712
713// ListDevicePorts returns the ports details for a specific device entry
714func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
715 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
716 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
717
718 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
719 agent := dMgr.getDeviceAgent(ctx, id.Id)
720 if agent == nil {
721 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
722 }
723
724 ports := agent.listDevicePorts()
725 ctr, ret := 0, make([]*voltha.Port, len(ports))
726 for _, port := range ports {
727 ret[ctr] = port
728 ctr++
729 }
730 return &voltha.Ports{Items: ret}, nil
731}
732
733// ListDevicePmConfigs returns pm configs of device
734func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
735 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
736 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
737
738 agent := dMgr.getDeviceAgent(ctx, id.Id)
739 if agent == nil {
740 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
741 }
742 return agent.listPmConfigs(ctx)
743}
744
745// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
746// following a user action
747func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
748 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
749 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
750
751 if configs.Id == "" {
752 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
753 }
754 agent := dMgr.getDeviceAgent(ctx, configs.Id)
755 if agent == nil {
756 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
757 }
758 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
759}
760
761// ListDeviceFlows returns the flow details for a specific device entry
762func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
763 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
764 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
765 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
766 agent := dMgr.getDeviceAgent(ctx, id.Id)
767 if agent == nil {
768 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
769 }
770
771 flows := agent.listDeviceFlows()
772 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
773 for _, flow := range flows {
774 ret[ctr] = flow
775 ctr++
776 }
777 return &ofp.Flows{Items: ret}, nil
778}
779
780// ListDeviceFlowGroups returns the flow group details for a specific device entry
khenaidoo9beaaf12021-10-19 17:32:01 -0400781func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*ofp.FlowGroups, error) {
khenaidood948f772021-08-11 17:49:24 -0400782 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
783 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
784 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
785 agent := dMgr.getDeviceAgent(ctx, id.Id)
786 if agent == nil {
787 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
788 }
789 groups := agent.listDeviceGroups()
790 ctr, ret := 0, make([]*ofp.OfpGroupEntry, len(groups))
791 for _, group := range groups {
792 ret[ctr] = group
793 ctr++
794 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400795 return &ofp.FlowGroups{Items: ret}, nil
khenaidood948f772021-08-11 17:49:24 -0400796}
797
798func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
799 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
800 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
801
802 logger.Debugw(ctx, "enable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
803 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
804 if agent == nil {
805 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
806 }
807 return &empty.Empty{}, agent.enablePort(ctx, port.PortNo)
808}
809
810func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
811 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
812 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
813
814 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
815 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
816 if agent == nil {
817 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
818 }
819 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
820}
821
khenaidoo9beaaf12021-10-19 17:32:01 -0400822func (dMgr *Manager) GetExtValue(ctx context.Context, value *extension.ValueSpecifier) (*extension.ReturnValues, error) {
khenaidood948f772021-08-11 17:49:24 -0400823 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
824 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
825
826 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
827 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
828 if err != nil {
829 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
830 }
831 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
832 if err != nil {
833 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
834 }
835 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
836 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
837 if err != nil {
838 return nil, err
839 }
840 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
841 return resp, nil
842 }
843 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
844
845}
846
847// SetExtValue set some given configs or value
khenaidoo9beaaf12021-10-19 17:32:01 -0400848func (dMgr *Manager) SetExtValue(ctx context.Context, value *extension.ValueSet) (*empty.Empty, error) {
khenaidood948f772021-08-11 17:49:24 -0400849 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
850 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
851
852 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
853 if err != nil {
854 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
855 }
856 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
857 resp, err := agent.setExtValue(ctx, device, value)
858 if err != nil {
859 return nil, err
860 }
861 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
862 return resp, nil
863 }
864 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
865
866}
867
khenaidoo9beaaf12021-10-19 17:32:01 -0400868func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *omci.OmciTestRequest) (*omci.TestResponse, error) {
khenaidood948f772021-08-11 17:49:24 -0400869 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
870 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
871
872 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
873 agent := dMgr.getDeviceAgent(ctx, request.Id)
874 if agent == nil {
875 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
876 }
877 return agent.startOmciTest(ctx, request)
878}
879
880func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
881 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
882
883 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
884 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
885 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
886 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
887 if agent == nil {
888 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
889 }
890 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
891 return nil, err
892 }
893 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
894}