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