blob: fc56c029322244ac7cbdcbb63edd7d9da58db511 [file] [log] [blame]
Mahir Gunyelfa6ea272020-06-10 17:03:51 -07001/*
2 * Copyright 2018-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 */
16
17package device
18
19import (
20 "context"
ssiddiquif076cb82021-04-23 10:47:04 +053021
22 "github.com/opencord/voltha-lib-go/v4/pkg/kafka"
Andrea Campanella025667e2021-01-14 11:50:07 +010023 "github.com/opencord/voltha-protos/v4/go/common"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070024
25 "github.com/gogo/protobuf/proto"
26 "github.com/golang/protobuf/ptypes"
Himani Chawlab4c25912020-11-12 17:16:38 +053027 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053028 "github.com/opencord/voltha-lib-go/v4/pkg/log"
29 "github.com/opencord/voltha-protos/v4/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070030 "google.golang.org/grpc/codes"
31 "google.golang.org/grpc/status"
32)
33
Andrea Campanella025667e2021-01-14 11:50:07 +010034func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070035 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
36 return nil, err
37 }
Himani Chawlab4c25912020-11-12 17:16:38 +053038 logger.Debugw(ctx, "download-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070039
Andrea Campanella025667e2021-01-14 11:50:07 +010040 if agent.device.Root {
Maninder0aabf0c2021-03-17 14:55:14 +053041 agent.requestQueue.RequestComplete()
Andrea Campanella025667e2021-01-14 11:50:07 +010042 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
43 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070044 }
Maninder0aabf0c2021-03-17 14:55:14 +053045 if !agent.proceedWithRequestNoLock() {
46 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +053047 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
Maninder0aabf0c2021-03-17 14:55:14 +053048 agent.deviceID)
49 }
Andrea Campanella025667e2021-01-14 11:50:07 +010050
51 device := agent.cloneDeviceWithoutLock()
52 if device.ImageDownloads != nil {
53 for _, image := range device.ImageDownloads {
54 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
55 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, already downloading image:%s",
56 agent.deviceID, image.Name)
57 }
58 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040059 }
60
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070061 // Save the image
62 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
63 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermanf6db9f12020-07-22 17:16:19 -040064 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanellac05c4c42021-02-11 10:25:28 +010065 _, index, err := getImage(img, device)
66 if err != nil {
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030067 cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
Andrea Campanellac05c4c42021-02-11 10:25:28 +010068 } else {
69 cloned.ImageDownloads[index] = clonedImg
70 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070071
Kent Hagermanf6db9f12020-07-22 17:16:19 -040072 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
73 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
74 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070075 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040076
77 // Send the request to the adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +000078 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +053079 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
80
Andrea Campanella025667e2021-01-14 11:50:07 +010081 ch, err := agent.adapterProxy.DownloadImage(subCtx, cloned, clonedImg)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040082 if err != nil {
83 cancel()
84 return nil, err
85 }
Andrea Campanella025667e2021-01-14 11:50:07 +010086 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onImageSuccess, agent.onImageFailure)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040087
Andrea Campanella025667e2021-01-14 11:50:07 +010088 return &common.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070089}
90
Andrea Campanella025667e2021-01-14 11:50:07 +010091// getImage is a helper method to figure out if an image is already registered
92func getImage(img *voltha.ImageDownload, device *voltha.Device) (*voltha.ImageDownload, int, error) {
93 for pos, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070094 if image.Id == img.Id && image.Name == img.Name {
Andrea Campanella025667e2021-01-14 11:50:07 +010095 return image, pos, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070096 }
97 }
Andrea Campanella025667e2021-01-14 11:50:07 +010098 return nil, -1, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s",
99 device.Id, img.Name)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700100}
101
Andrea Campanella025667e2021-01-14 11:50:07 +0100102func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700103 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
104 return nil, err
105 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530106 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700107
Maninder0aabf0c2021-03-17 14:55:14 +0530108 if !agent.proceedWithRequestNoLock() {
109 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +0530110 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530111 agent.deviceID)
112 }
113
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700114 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400115 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100116 _, index, err := getImage(img, cloned)
117 if err != nil {
118 agent.requestQueue.RequestComplete()
119 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700120 }
121
Andrea Campanella025667e2021-01-14 11:50:07 +0100122 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
123
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400124 if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
125 agent.requestQueue.RequestComplete()
126 } else {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700127 // Set the device to Enabled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400128 cloned.AdminState = voltha.AdminState_ENABLED
129 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700130 return nil, err
131 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000132 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530133 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
134
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400135 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700136 if err != nil {
137 cancel()
138 return nil, err
139 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100140 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onImageSuccess,
141 agent.onImageFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700142 }
143 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
144}
145
146func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
147 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
148 return nil, err
149 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530150 logger.Debugw(ctx, "activate-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700151
Maninder0aabf0c2021-03-17 14:55:14 +0530152 if !agent.proceedWithRequestNoLock() {
153 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +0530154 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530155 agent.deviceID)
156 }
157
Andrea Campanella025667e2021-01-14 11:50:07 +0100158 // Update image download state
159 cloned := agent.cloneDeviceWithoutLock()
160 image, index, err := getImage(img, cloned)
161 if err != nil {
162 agent.requestQueue.RequestComplete()
163 return nil, err
164 }
165
Andrea Campanella025667e2021-01-14 11:50:07 +0100166 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
167 agent.requestQueue.RequestComplete()
168 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-has-not-downloaded-image:%s", agent.deviceID, img.Name)
169 }
170
171 //TODO does this need to be removed ?
172 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400173 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700174 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
175 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400176
Andrea Campanella025667e2021-01-14 11:50:07 +0100177 // Save the image
178 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
179
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400180 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
181 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700182 return nil, err
183 }
184
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000185 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530186 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
187
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400188 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700189 if err != nil {
190 cancel()
191 return nil, err
192 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100193 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onImageSuccess, agent.onFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700194
195 // The status of the AdminState will be changed following the update_download_status response from the adapter
196 // The image name will also be removed from the device list
197 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
198}
199
200func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
201 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
202 return nil, err
203 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530204 logger.Debugw(ctx, "revert-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700205
Andrea Campanella025667e2021-01-14 11:50:07 +0100206 // Update image download state
207 cloned := agent.cloneDeviceWithoutLock()
208 _, index, err := getImage(img, cloned)
209 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400210 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700211 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
212 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100213 if cloned.AdminState != voltha.AdminState_ENABLED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400214 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700215 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
216 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100217
218 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_REVERTING
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700219
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400220 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700221 return nil, err
222 }
223
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000224 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530225 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
226
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400227 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700228 if err != nil {
229 cancel()
230 return nil, err
231 }
232 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
233
234 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
235}
236
237func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530238 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700239
240 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
241 return nil, err
242 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400243 device := agent.getDeviceReadOnlyWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700244 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
245 agent.requestQueue.RequestComplete()
246 if err != nil {
247 return nil, err
248 }
249 // Wait for the adapter response
250 rpcResponse, ok := <-ch
251 if !ok {
252 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
253 }
254 if rpcResponse.Err != nil {
255 return nil, rpcResponse.Err
256 }
257 // Successful response
258 imgDownload := &voltha.ImageDownload{}
259 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
260 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
261 }
262 return imgDownload, nil
263}
264
265func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
266 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
267 return err
268 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000269 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700270
Maninder0aabf0c2021-03-17 14:55:14 +0530271 if !agent.proceedWithRequestNoLock() {
272 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +0530273 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530274 agent.deviceID)
275 }
276
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700277 // Update the image as well as remove it if the download was cancelled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400278 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700279 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
280 for _, image := range cloned.ImageDownloads {
281 if image.Id == img.Id && image.Name == img.Name {
282 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
283 clonedImages = append(clonedImages, img)
284 }
285 }
286 }
287 cloned.ImageDownloads = clonedImages
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400288
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700289 // Set the Admin state to enabled if required
290 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
291 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400292 img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
293 cloned.AdminState = voltha.AdminState_ENABLED
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700294 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400295 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700296}
297
298func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530299 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700300
Kent Hagermancba2f302020-07-28 13:37:36 -0400301 device, err := agent.getDeviceReadOnly(ctx)
302 if err != nil {
303 return nil, status.Errorf(codes.Aborted, "%s", err)
304 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400305 for _, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700306 if image.Id == img.Id && image.Name == img.Name {
307 return image, nil
308 }
309 }
310 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
311}
312
313func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530314 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700315
Kent Hagermancba2f302020-07-28 13:37:36 -0400316 device, err := agent.getDeviceReadOnly(ctx)
317 if err != nil {
318 return nil, status.Errorf(codes.Aborted, "%s", err)
319 }
320 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700321}
Andrea Campanella025667e2021-01-14 11:50:07 +0100322
323// onImageFailure brings back the device to Enabled state and sets the image to image download_failed.
324func (agent *Agent) onImageFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100325 // original context has failed due to timeout , let's open a new one
326 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
327 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
Maninder0aabf0c2021-03-17 14:55:14 +0530328 defer cancel()
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100329
330 if err := agent.requestQueue.WaitForGreenLight(subCtx); err != nil {
331 logger.Errorw(subCtx, "can't obtain lock", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": err, "args": reqArgs})
Maninder0aabf0c2021-03-17 14:55:14 +0530332 return
333 }
334 if !agent.proceedWithRequestNoLock() {
335 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +0530336 logger.Errorw(subCtx, "Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
337 log.Fields{"rpc": rpc, "device-id": agent.deviceID})
Andrea Campanella025667e2021-01-14 11:50:07 +0100338 return
339 }
340 if res, ok := response.(error); ok {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100341 logger.Errorw(subCtx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
342 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100343 //TODO base this on IMAGE ID when created
344 var imageFailed *voltha.ImageDownload
345 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100346 if cloned.ImageDownloads != nil {
347 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100348 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
349 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
350 imageFailed = image
351 index = pos
352 }
353 }
354 }
355
356 if imageFailed == nil {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100357 logger.Errorw(subCtx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanella025667e2021-01-14 11:50:07 +0100358 return
359 }
360
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100361 //update image state on failure
Andrea Campanella025667e2021-01-14 11:50:07 +0100362 if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100363 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
Andrea Campanella025667e2021-01-14 11:50:07 +0100364 } else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100365 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_INACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100366 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100367 //Enabled is the only state we can go back to.
368 cloned.AdminState = voltha.AdminState_ENABLED
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100369 if err := agent.updateDeviceAndReleaseLock(subCtx, cloned); err != nil {
370 logger.Errorw(subCtx, "failed-enable-device-after-image-failure",
Andrea Campanella025667e2021-01-14 11:50:07 +0100371 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
372 }
373 } else {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100374 logger.Errorw(subCtx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100375 return
Andrea Campanella025667e2021-01-14 11:50:07 +0100376 }
377 // TODO: Post failure message onto kafka
378}
379
380// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
381func (agent *Agent) onImageSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
382 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530383 logger.Errorw(ctx, "cannot-obtain-lock", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": err, "args": reqArgs})
Andrea Campanella025667e2021-01-14 11:50:07 +0100384 return
385 }
Maninder0aabf0c2021-03-17 14:55:14 +0530386 if !agent.proceedWithRequestNoLock() {
387 agent.requestQueue.RequestComplete()
Maninder581cf4b2021-06-16 22:42:07 +0530388 logger.Errorw(ctx, "Cannot complete operation as Device deletion/reconciling is in progress or reconcile failed.",
389 log.Fields{"rpc": rpc, "device-id": agent.deviceID})
Maninder0aabf0c2021-03-17 14:55:14 +0530390 return
391 }
Matteo Scandolo03686da2021-03-09 13:16:55 -0800392 logger.Infow(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100393 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100394 //TODO base this on IMAGE ID when created
395 var imageSucceeded *voltha.ImageDownload
396 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100397 if cloned.ImageDownloads != nil {
398 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100399 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
400 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
401 imageSucceeded = image
402 index = pos
403 }
404 }
405 }
406
407 if imageSucceeded == nil {
408 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
409 return
410 }
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100411 //update image state on success
Andrea Campanella025667e2021-01-14 11:50:07 +0100412 if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100413 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
Andrea Campanella025667e2021-01-14 11:50:07 +0100414 } else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100415 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100416 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100417 //Enabled is the only state we can go back to.
418 cloned.AdminState = voltha.AdminState_ENABLED
419 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
420 logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
421 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
422 }
423
424}
ssiddiquif076cb82021-04-23 10:47:04 +0530425
426func (agent *Agent) downloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
427 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
428 return nil, err
429 }
430
431 logger.Debugw(ctx, "download-image-to-device", log.Fields{"device-id": agent.deviceID})
432 if agent.device.Root {
433 agent.requestQueue.RequestComplete()
434 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
435 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
436 }
437
438 cloned := agent.cloneDeviceWithoutLock()
439
440 // Send the request to the adapter
441 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
442 defer cancel()
443 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
444
445 ch, err := agent.adapterProxy.DownloadImageToOnuDevice(subCtx, cloned, request)
446 agent.requestQueue.RequestComplete()
447 if err != nil {
448 return nil, err
449 }
450
451 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
452}
453
454func (agent *Agent) getImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
455 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
456 return nil, err
457 }
458
459 cloned := agent.cloneDeviceWithoutLock()
460
461 // Send the request to the adapter
462 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
463 defer cancel()
464 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
465 logger.Debugw(ctx, "get-image-status", log.Fields{"device-id": agent.deviceID})
466
467 ch, err := agent.adapterProxy.GetOnuImageStatus(subCtx, cloned, request)
468 agent.requestQueue.RequestComplete()
469 if err != nil {
470 return nil, err
471 }
472
473 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
474}
475
476func (agent *Agent) activateImageOnDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
477 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
478 return nil, err
479 }
480
481 cloned := agent.cloneDeviceWithoutLock()
482
483 // Send the request to the adapter
484 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
485 defer cancel()
486 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
487 logger.Debugw(ctx, "activate-image-on-device", log.Fields{"device-id": agent.deviceID})
488
489 ch, err := agent.adapterProxy.ActivateOnuImage(subCtx, cloned, request)
490 agent.requestQueue.RequestComplete()
491 if err != nil {
492 return nil, err
493 }
494
495 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
496}
497
498func (agent *Agent) abortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
499 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
500 return nil, err
501 }
502
503 cloned := agent.cloneDeviceWithoutLock()
504
505 // Send the request to the adapter
506 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
507 defer cancel()
508 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
509 logger.Debugw(ctx, "abort-image-on-device", log.Fields{"device-id": agent.deviceID})
510
511 ch, err := agent.adapterProxy.AbortImageUpgrade(subCtx, cloned, request)
512 agent.requestQueue.RequestComplete()
513 if err != nil {
514 return nil, err
515 }
516
517 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
518}
519
520func (agent *Agent) commitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
521 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
522 return nil, err
523 }
524
525 cloned := agent.cloneDeviceWithoutLock()
526
527 // Send the request to the adapter
528 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
529 defer cancel()
530 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
531 logger.Debugw(ctx, "commit-image-on-device", log.Fields{"device-id": agent.deviceID})
532
533 ch, err := agent.adapterProxy.CommitImage(subCtx, cloned, request)
534 agent.requestQueue.RequestComplete()
535 if err != nil {
536 return nil, err
537 }
538
539 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
540}
541
542func (agent *Agent) getOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
543 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
544 return nil, err
545 }
546
547 cloned := agent.cloneDeviceWithoutLock()
548
549 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
550 defer cancel()
551 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
ssiddiqui47348f62021-05-20 20:41:15 +0530552 logger.Debug(ctx, "get-onu-images")
ssiddiquif076cb82021-04-23 10:47:04 +0530553
554 // Send the request to the adapter
555 ch, err := agent.adapterProxy.GetOnuImages(subCtx, cloned, id)
556 agent.requestQueue.RequestComplete()
557 if err != nil {
558 return nil, err
559 }
560
561 //wait for adapter response
562 select {
563 case rpcResponse, ok := <-ch:
564 if !ok {
565 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
566 } else if rpcResponse.Err != nil {
567 // return error
568 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
569 } else {
570 resp := &voltha.OnuImages{}
571 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
572 return nil, status.Errorf(codes.Internal, "%s", err.Error())
573 }
574
575 return resp, nil
576 }
577 case <-ctx.Done():
578 return nil, ctx.Err()
579 }
580}
581
582func (agent *Agent) getDeviceImageResponseFromAdapter(ctx context.Context, ch chan *kafka.RpcResponse) (*voltha.DeviceImageResponse, error) {
583 //wait for adapter response
584 select {
585 case rpcResponse, ok := <-ch:
586 if !ok {
587 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
588 } else if rpcResponse.Err != nil {
589 // return error
590 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
591 } else {
592 resp := &voltha.DeviceImageResponse{}
593 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
594 return nil, status.Errorf(codes.Internal, "%s", err.Error())
595 }
596
597 if len(resp.DeviceImageStates) == 0 || resp.DeviceImageStates[0] == nil {
598 return nil, status.Errorf(codes.Internal, "invalid response from adapter")
599 }
600
601 return resp, nil
602 }
603 case <-ctx.Done():
604 return nil, ctx.Err()
605 }
606}