blob: 8b3848dbf1ad639018f2626b1de4db43007fb23a [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()))
Elia Battiston58d1c062022-02-08 11:54:27 +0100348
349 if request.DeviceId == nil {
350 //Reply for every ONU
351 dMgr.deviceAgents.Range(func(key, value interface{}) bool {
352 device := value.(*Agent).device
353 if !device.Root {
354 request.DeviceId = append(request.DeviceId, &common.ID{Id: value.(*Agent).device.Id})
355 }
356 return true
357 })
358 }
359
khenaidood948f772021-08-11 17:49:24 -0400360 for index, deviceID := range request.DeviceId {
361 // Create status request per device
362 imageStatusReq := &voltha.DeviceImageRequest{
363 Version: request.Version,
364 CommitOnSuccess: request.CommitOnSuccess,
365 }
366
367 //slice-out only single deviceID from the request
368 imageStatusReq.DeviceId = request.DeviceId[index : index+1]
369
370 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
371 agent := dMgr.getDeviceAgent(ctx, deviceID)
372 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530373 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
374 ch <- []*voltha.DeviceImageState{{
375 DeviceId: deviceID,
376 ImageState: &voltha.ImageState{
377 Version: request.GetVersion(),
378 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
379 Reason: voltha.ImageState_UNKNOWN_ERROR,
380 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
381 },
382 }}
khenaidood948f772021-08-11 17:49:24 -0400383 return
384 }
385
386 resp, err := agent.getImageStatus(ctx, req)
387 if err != nil {
388 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530389 ch <- []*voltha.DeviceImageState{{
390 DeviceId: deviceID,
391 ImageState: &voltha.ImageState{
392 Version: request.GetVersion(),
393 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
394 Reason: voltha.ImageState_UNKNOWN_ERROR,
395 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
396 },
397 }}
khenaidood948f772021-08-11 17:49:24 -0400398 return
399 }
400
401 err = dMgr.validateDeviceImageResponse(resp)
402 if err != nil {
403 logger.Errorw(ctx, "get-image-status-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530404 ch <- []*voltha.DeviceImageState{{
405 DeviceId: deviceID,
406 ImageState: &voltha.ImageState{
407 Version: request.GetVersion(),
408 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
409 Reason: voltha.ImageState_UNKNOWN_ERROR,
410 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
411 },
412 }}
khenaidood948f772021-08-11 17:49:24 -0400413 return
414 }
415 ch <- resp.GetDeviceImageStates()
416 }(deviceID.GetId(), imageStatusReq, respCh)
417
418 }
419
420 return dMgr.waitForAllResponses(ctx, "get-image-status", respCh, len(request.GetDeviceId()))
421}
422
423func (dMgr *Manager) AbortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
424 if err := dMgr.validateImageRequest(request); err != nil {
425 return nil, err
426 }
427
428 ctx = utils.WithRPCMetadataContext(ctx, "AbortImageUpgradeToDevice")
429 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
430
431 for index, deviceID := range request.DeviceId {
432 // Create abort request per device
433 abortImageReq := &voltha.DeviceImageRequest{
434 Version: request.Version,
435 CommitOnSuccess: request.CommitOnSuccess,
436 }
437
438 //slice-out only single deviceID from the request
439 abortImageReq.DeviceId = request.DeviceId[index : index+1]
440
441 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
442 agent := dMgr.getDeviceAgent(ctx, deviceID)
443 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530444 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
445 ch <- []*voltha.DeviceImageState{{
446 DeviceId: deviceID,
447 ImageState: &voltha.ImageState{
448 Version: request.GetVersion(),
449 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
450 Reason: voltha.ImageState_UNKNOWN_ERROR,
451 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
452 },
453 }}
khenaidood948f772021-08-11 17:49:24 -0400454 return
455 }
456
457 resp, err := agent.abortImageUpgradeToDevice(ctx, req)
458 if err != nil {
459 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530460 ch <- []*voltha.DeviceImageState{{
461 DeviceId: deviceID,
462 ImageState: &voltha.ImageState{
463 Version: request.GetVersion(),
464 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
465 Reason: voltha.ImageState_UNKNOWN_ERROR,
466 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
467 },
468 }}
khenaidood948f772021-08-11 17:49:24 -0400469 return
470 }
471
472 err = dMgr.validateDeviceImageResponse(resp)
473 if err != nil {
474 logger.Errorw(ctx, "abort-image-upgrade-to-device-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530475 ch <- []*voltha.DeviceImageState{{
476 DeviceId: deviceID,
477 ImageState: &voltha.ImageState{
478 Version: request.GetVersion(),
479 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
480 Reason: voltha.ImageState_UNKNOWN_ERROR,
481 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
482 },
483 }}
khenaidood948f772021-08-11 17:49:24 -0400484 return
485 }
486 ch <- resp.GetDeviceImageStates()
487 }(deviceID.GetId(), abortImageReq, respCh)
488
489 }
490
491 return dMgr.waitForAllResponses(ctx, "abort-image-upgrade-to-device", respCh, len(request.GetDeviceId()))
492}
493
494func (dMgr *Manager) GetOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
495 if id == nil || id.Id == "" {
496 return nil, status.Errorf(codes.InvalidArgument, "empty device id")
497 }
498
499 ctx = utils.WithRPCMetadataContext(ctx, "GetOnuImages")
500 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
501 agent := dMgr.getDeviceAgent(ctx, id.Id)
502 if agent == nil {
503 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
504 }
505
506 resp, err := agent.getOnuImages(ctx, id)
507 if err != nil {
508 return nil, err
509 }
510
511 logger.Debugw(ctx, "get-onu-images-result", log.Fields{"onu-image": resp.Items})
512
513 return resp, nil
514}
515
516func (dMgr *Manager) ActivateImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
517 if err := dMgr.validateImageRequest(request); err != nil {
518 return nil, err
519 }
520
521 ctx = utils.WithRPCMetadataContext(ctx, "ActivateImage")
522 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
523
524 for index, deviceID := range request.DeviceId {
525 // Create activate request per device
526 activateImageReq := &voltha.DeviceImageRequest{
527 Version: request.Version,
528 CommitOnSuccess: request.CommitOnSuccess,
529 }
530
531 //slice-out only single deviceID from the request
532 activateImageReq.DeviceId = request.DeviceId[index : index+1]
533
534 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
535 agent := dMgr.getDeviceAgent(ctx, deviceID)
536 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530537 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
538 ch <- []*voltha.DeviceImageState{{
539 DeviceId: deviceID,
540 ImageState: &voltha.ImageState{
541 Version: request.GetVersion(),
542 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
543 Reason: voltha.ImageState_UNKNOWN_ERROR,
544 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
545 },
546 }}
khenaidood948f772021-08-11 17:49:24 -0400547 return
548 }
549
550 resp, err := agent.activateImageOnDevice(ctx, req)
551 if err != nil {
552 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530553 ch <- []*voltha.DeviceImageState{{
554 DeviceId: deviceID,
555 ImageState: &voltha.ImageState{
556 Version: request.GetVersion(),
557 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
558 Reason: voltha.ImageState_UNKNOWN_ERROR,
559 ImageState: voltha.ImageState_IMAGE_ACTIVATION_ABORTED,
560 },
561 }}
khenaidood948f772021-08-11 17:49:24 -0400562 return
563 }
564
565 err = dMgr.validateDeviceImageResponse(resp)
566 if err != nil {
567 logger.Errorw(ctx, "activate-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530568 ch <- []*voltha.DeviceImageState{{
569 DeviceId: deviceID,
570 ImageState: &voltha.ImageState{
571 Version: request.GetVersion(),
572 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
573 Reason: voltha.ImageState_UNKNOWN_ERROR,
574 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
575 },
576 }}
khenaidood948f772021-08-11 17:49:24 -0400577 return
578 }
579
580 ch <- resp.GetDeviceImageStates()
581 }(deviceID.GetId(), activateImageReq, respCh)
582
583 }
584
585 return dMgr.waitForAllResponses(ctx, "activate-image", respCh, len(request.GetDeviceId()))
586}
587
588func (dMgr *Manager) CommitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
589 if err := dMgr.validateImageRequest(request); err != nil {
590 return nil, err
591 }
592
593 ctx = utils.WithRPCMetadataContext(ctx, "CommitImage")
594 respCh := make(chan []*voltha.DeviceImageState, len(request.GetDeviceId()))
595
596 for index, deviceID := range request.DeviceId {
597 // Create commit request per device
598 commitImageReq := &voltha.DeviceImageRequest{
599 Version: request.Version,
600 CommitOnSuccess: request.CommitOnSuccess,
601 }
602 //slice-out only single deviceID from the request
603 commitImageReq.DeviceId = request.DeviceId[index : index+1]
604
605 go func(deviceID string, req *voltha.DeviceImageRequest, ch chan []*voltha.DeviceImageState) {
606 agent := dMgr.getDeviceAgent(ctx, deviceID)
607 if agent == nil {
ssiddiqui9e120e92021-10-11 12:33:05 +0530608 logger.Errorw(ctx, "Device-agent-not-found", log.Fields{"device-id": deviceID})
609 ch <- []*voltha.DeviceImageState{{
610 DeviceId: deviceID,
611 ImageState: &voltha.ImageState{
612 Version: request.GetVersion(),
613 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
614 Reason: voltha.ImageState_UNKNOWN_ERROR,
615 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
616 },
617 }}
khenaidood948f772021-08-11 17:49:24 -0400618 return
619 }
620
621 resp, err := agent.commitImage(ctx, req)
622 if err != nil {
623 logger.Errorw(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530624 ch <- []*voltha.DeviceImageState{{
625 DeviceId: deviceID,
626 ImageState: &voltha.ImageState{
627 Version: request.GetVersion(),
628 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
629 Reason: voltha.ImageState_UNKNOWN_ERROR,
630 ImageState: voltha.ImageState_IMAGE_COMMIT_ABORTED,
631 },
632 }}
khenaidood948f772021-08-11 17:49:24 -0400633 return
634 }
635
636 err = dMgr.validateDeviceImageResponse(resp)
637 if err != nil {
638 logger.Errorf(ctx, "commit-image-failed", log.Fields{"device-id": deviceID, "error": err})
ssiddiqui9e120e92021-10-11 12:33:05 +0530639 ch <- []*voltha.DeviceImageState{{
640 DeviceId: deviceID,
641 ImageState: &voltha.ImageState{
642 Version: request.GetVersion(),
643 DownloadState: voltha.ImageState_DOWNLOAD_UNKNOWN,
644 Reason: voltha.ImageState_UNKNOWN_ERROR,
645 ImageState: voltha.ImageState_IMAGE_UNKNOWN,
646 },
647 }}
khenaidood948f772021-08-11 17:49:24 -0400648 return
649 }
650 ch <- resp.GetDeviceImageStates()
651 }(deviceID.GetId(), commitImageReq, respCh)
652
653 }
654
655 return dMgr.waitForAllResponses(ctx, "commit-image", respCh, len(request.GetDeviceId()))
656}
657
658// convenience to avoid redefining
659var imageDownloadFailureResp = &voltha.ImageDownload{DownloadState: voltha.ImageDownload_DOWNLOAD_UNKNOWN}
660
661// GetImageDownloadStatus returns status of image download
662func (dMgr *Manager) GetImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
663 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownloadStatus")
664 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
665
666 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": img.Id, "image-name": img.Name})
667 agent := dMgr.getDeviceAgent(ctx, img.Id)
668 if agent == nil {
669 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
670 }
671 resp, err := agent.getImageDownloadStatus(ctx, img)
672 if err != nil {
673 return imageDownloadFailureResp, err
674 }
675 return resp, nil
676}
677
678// GetImageDownload returns image download
679func (dMgr *Manager) GetImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
680 ctx = utils.WithRPCMetadataContext(ctx, "GetImageDownload")
681 log.EnrichSpan(ctx, log.Fields{"device-id": img.Id})
682
683 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": img.Id, "image-name": img.Name})
684 agent := dMgr.getDeviceAgent(ctx, img.Id)
685 if agent == nil {
686 return imageDownloadFailureResp, status.Errorf(codes.NotFound, "%s", img.Id)
687 }
688 resp, err := agent.getImageDownload(ctx, img)
689 if err != nil {
690 return imageDownloadFailureResp, err
691 }
692 return resp, nil
693}
694
695// ListImageDownloads returns image downloads
696func (dMgr *Manager) ListImageDownloads(ctx context.Context, id *voltha.ID) (*voltha.ImageDownloads, error) {
697 ctx = utils.WithRPCMetadataContext(ctx, "ListImageDownloads")
698 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
699
700 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": id.Id})
701 agent := dMgr.getDeviceAgent(ctx, id.Id)
702 if agent == nil {
703 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, status.Errorf(codes.NotFound, "%s", id.Id)
704 }
705 resp, err := agent.listImageDownloads(ctx, id.Id)
706 if err != nil {
707 return &voltha.ImageDownloads{Items: []*voltha.ImageDownload{imageDownloadFailureResp}}, err
708 }
709 return resp, nil
710}
711
712// GetImages returns all images for a specific device entry
713func (dMgr *Manager) GetImages(ctx context.Context, id *voltha.ID) (*voltha.Images, error) {
714 ctx = utils.WithRPCMetadataContext(ctx, "GetImages")
715 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
716
717 logger.Debugw(ctx, "get-images", log.Fields{"device-id": id.Id})
718 device, err := dMgr.getDeviceReadOnly(ctx, id.Id)
719 if err != nil {
720 return nil, err
721 }
722 return device.Images, nil
723}
724
725// ListDevicePorts returns the ports details for a specific device entry
726func (dMgr *Manager) ListDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.Ports, error) {
727 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePorts")
728 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
729
730 logger.Debugw(ctx, "list-device-ports", log.Fields{"device-id": id.Id})
731 agent := dMgr.getDeviceAgent(ctx, id.Id)
732 if agent == nil {
733 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
734 }
735
736 ports := agent.listDevicePorts()
737 ctr, ret := 0, make([]*voltha.Port, len(ports))
738 for _, port := range ports {
739 ret[ctr] = port
740 ctr++
741 }
742 return &voltha.Ports{Items: ret}, nil
743}
744
745// ListDevicePmConfigs returns pm configs of device
746func (dMgr *Manager) ListDevicePmConfigs(ctx context.Context, id *voltha.ID) (*voltha.PmConfigs, error) {
747 ctx = utils.WithRPCMetadataContext(ctx, "ListDevicePmConfigs")
748 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
749
750 agent := dMgr.getDeviceAgent(ctx, id.Id)
751 if agent == nil {
752 return nil, status.Errorf(codes.NotFound, "%s", id.Id)
753 }
754 return agent.listPmConfigs(ctx)
755}
756
757// UpdateDevicePmConfigs updates the PM configs. This is executed when the northbound gRPC API is invoked, typically
758// following a user action
759func (dMgr *Manager) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
760 ctx = utils.WithRPCMetadataContext(ctx, "UpdateDevicePmConfigs")
761 log.EnrichSpan(ctx, log.Fields{"device-id": configs.Id})
762
763 if configs.Id == "" {
764 return nil, status.Error(codes.FailedPrecondition, "invalid-device-Id")
765 }
766 agent := dMgr.getDeviceAgent(ctx, configs.Id)
767 if agent == nil {
768 return nil, status.Errorf(codes.NotFound, "%s", configs.Id)
769 }
770 return &empty.Empty{}, agent.updatePmConfigs(ctx, configs)
771}
772
773// ListDeviceFlows returns the flow details for a specific device entry
774func (dMgr *Manager) ListDeviceFlows(ctx context.Context, id *voltha.ID) (*ofp.Flows, error) {
775 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlows")
776 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
777 logger.Debugw(ctx, "list-device-flows", log.Fields{"device-id": id.Id})
778 agent := dMgr.getDeviceAgent(ctx, id.Id)
779 if agent == nil {
780 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
781 }
782
783 flows := agent.listDeviceFlows()
784 ctr, ret := 0, make([]*ofp.OfpFlowStats, len(flows))
785 for _, flow := range flows {
786 ret[ctr] = flow
787 ctr++
788 }
789 return &ofp.Flows{Items: ret}, nil
790}
791
792// ListDeviceFlowGroups returns the flow group details for a specific device entry
khenaidoo9beaaf12021-10-19 17:32:01 -0400793func (dMgr *Manager) ListDeviceFlowGroups(ctx context.Context, id *voltha.ID) (*ofp.FlowGroups, error) {
khenaidood948f772021-08-11 17:49:24 -0400794 ctx = utils.WithRPCMetadataContext(ctx, "ListDeviceFlowGroups")
795 log.EnrichSpan(ctx, log.Fields{"device-id": id.Id})
796 logger.Debugw(ctx, "list-device-flow-groups", log.Fields{"device-id": id.Id})
797 agent := dMgr.getDeviceAgent(ctx, id.Id)
798 if agent == nil {
799 return nil, status.Errorf(codes.NotFound, "device-%s", id.Id)
800 }
801 groups := agent.listDeviceGroups()
802 ctr, ret := 0, make([]*ofp.OfpGroupEntry, len(groups))
803 for _, group := range groups {
804 ret[ctr] = group
805 ctr++
806 }
khenaidoo9beaaf12021-10-19 17:32:01 -0400807 return &ofp.FlowGroups{Items: ret}, nil
khenaidood948f772021-08-11 17:49:24 -0400808}
809
810func (dMgr *Manager) EnablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
811 ctx = utils.WithRPCMetadataContext(ctx, "EnablePort")
812 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
813
814 logger.Debugw(ctx, "enable-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.enablePort(ctx, port.PortNo)
820}
821
822func (dMgr *Manager) DisablePort(ctx context.Context, port *voltha.Port) (*empty.Empty, error) {
823 ctx = utils.WithRPCMetadataContext(ctx, "DisablePort")
824 log.EnrichSpan(ctx, log.Fields{"device-id": port.DeviceId})
825
826 logger.Debugw(ctx, "disable-port", log.Fields{"device-id": port.DeviceId, "port-no": port.PortNo})
827 agent := dMgr.getDeviceAgent(ctx, port.DeviceId)
828 if agent == nil {
829 return nil, status.Errorf(codes.NotFound, "%s", port.DeviceId)
830 }
831 return &empty.Empty{}, agent.disablePort(ctx, port.PortNo)
832}
833
khenaidoo9beaaf12021-10-19 17:32:01 -0400834func (dMgr *Manager) GetExtValue(ctx context.Context, value *extension.ValueSpecifier) (*extension.ReturnValues, error) {
khenaidood948f772021-08-11 17:49:24 -0400835 ctx = utils.WithRPCMetadataContext(ctx, "GetExtValue")
836 log.EnrichSpan(ctx, log.Fields{"device-id": value.Id})
837
838 logger.Debugw(ctx, "get-ext-value", log.Fields{"onu-id": value.Id})
839 cDevice, err := dMgr.getDeviceReadOnly(ctx, value.Id)
840 if err != nil {
841 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
842 }
843 pDevice, err := dMgr.getDeviceReadOnly(ctx, cDevice.ParentId)
844 if err != nil {
845 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
846 }
847 if agent := dMgr.getDeviceAgent(ctx, cDevice.ParentId); agent != nil {
848 resp, err := agent.getExtValue(ctx, pDevice, cDevice, value)
849 if err != nil {
850 return nil, err
851 }
852 logger.Debugw(ctx, "get-ext-value-result", log.Fields{"result": resp})
853 return resp, nil
854 }
855 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
856
857}
858
859// SetExtValue set some given configs or value
khenaidoo9beaaf12021-10-19 17:32:01 -0400860func (dMgr *Manager) SetExtValue(ctx context.Context, value *extension.ValueSet) (*empty.Empty, error) {
khenaidood948f772021-08-11 17:49:24 -0400861 ctx = utils.WithRPCMetadataContext(ctx, "SetExtValue")
862 logger.Debugw(ctx, "set-ext-value", log.Fields{"onu-id": value.Id})
863
864 device, err := dMgr.getDeviceReadOnly(ctx, value.Id)
865 if err != nil {
866 return nil, status.Errorf(codes.Aborted, "%s", err.Error())
867 }
868 if agent := dMgr.getDeviceAgent(ctx, device.Id); agent != nil {
869 resp, err := agent.setExtValue(ctx, device, value)
870 if err != nil {
871 return nil, err
872 }
873 logger.Debugw(ctx, "set-ext-value-result", log.Fields{"result": resp})
874 return resp, nil
875 }
876 return nil, status.Errorf(codes.NotFound, "%s", value.Id)
877
878}
879
khenaidoo9beaaf12021-10-19 17:32:01 -0400880func (dMgr *Manager) StartOmciTestAction(ctx context.Context, request *omci.OmciTestRequest) (*omci.TestResponse, error) {
khenaidood948f772021-08-11 17:49:24 -0400881 ctx = utils.WithRPCMetadataContext(ctx, "StartOmciTestAction")
882 log.EnrichSpan(ctx, log.Fields{"device-id": request.Id})
883
884 logger.Debugw(ctx, "start-omci-test-action", log.Fields{"device-id": request.Id, "uuid": request.Uuid})
885 agent := dMgr.getDeviceAgent(ctx, request.Id)
886 if agent == nil {
887 return nil, status.Errorf(codes.NotFound, "%s", request.Id)
888 }
889 return agent.startOmciTest(ctx, request)
890}
891
892func (dMgr *Manager) SimulateAlarm(ctx context.Context, simulateReq *voltha.SimulateAlarmRequest) (*common.OperationResp, error) {
893 ctx = utils.WithRPCMetadataContext(ctx, "SimulateAlarm")
894
895 logger.Debugw(ctx, "simulate-alarm", log.Fields{"id": simulateReq.Id, "indicator": simulateReq.Indicator, "intf-id": simulateReq.IntfId,
896 "port-type-name": simulateReq.PortTypeName, "onu-device-id": simulateReq.OnuDeviceId, "inverse-bit-error-rate": simulateReq.InverseBitErrorRate,
897 "drift": simulateReq.Drift, "new-eqd": simulateReq.NewEqd, "onu-serial-number": simulateReq.OnuSerialNumber, "operation": simulateReq.Operation})
898 agent := dMgr.getDeviceAgent(ctx, simulateReq.Id)
899 if agent == nil {
900 return nil, status.Errorf(codes.NotFound, "%s", simulateReq.Id)
901 }
902 if err := agent.simulateAlarm(ctx, simulateReq); err != nil {
903 return nil, err
904 }
905 return &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}, nil
906}