blob: 075e2bfdbb7f52f6524ebead7d401fa98aed3f19 [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()
47 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling or deletion is in progress.",
48 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()
110 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling or deletion is in progress.",
111 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()
154 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling or deletion is in progress.",
155 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()
273 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Device reconciling or deletion is in progress.",
274 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()
Andrea Campanella025667e2021-01-14 11:50:07 +0100336 return
337 }
338 if res, ok := response.(error); ok {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100339 logger.Errorw(subCtx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
340 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100341 //TODO base this on IMAGE ID when created
342 var imageFailed *voltha.ImageDownload
343 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100344 if cloned.ImageDownloads != nil {
345 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100346 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
347 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
348 imageFailed = image
349 index = pos
350 }
351 }
352 }
353
354 if imageFailed == nil {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100355 logger.Errorw(subCtx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanella025667e2021-01-14 11:50:07 +0100356 return
357 }
358
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100359 //update image state on failure
Andrea Campanella025667e2021-01-14 11:50:07 +0100360 if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100361 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
Andrea Campanella025667e2021-01-14 11:50:07 +0100362 } else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100363 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_INACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100364 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100365 //Enabled is the only state we can go back to.
366 cloned.AdminState = voltha.AdminState_ENABLED
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100367 if err := agent.updateDeviceAndReleaseLock(subCtx, cloned); err != nil {
368 logger.Errorw(subCtx, "failed-enable-device-after-image-failure",
Andrea Campanella025667e2021-01-14 11:50:07 +0100369 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
370 }
371 } else {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100372 logger.Errorw(subCtx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100373 return
Andrea Campanella025667e2021-01-14 11:50:07 +0100374 }
375 // TODO: Post failure message onto kafka
376}
377
378// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
379func (agent *Agent) onImageSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
380 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530381 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 +0100382 return
383 }
Maninder0aabf0c2021-03-17 14:55:14 +0530384 if !agent.proceedWithRequestNoLock() {
385 agent.requestQueue.RequestComplete()
386 return
387 }
Matteo Scandolo03686da2021-03-09 13:16:55 -0800388 logger.Infow(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100389 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100390 //TODO base this on IMAGE ID when created
391 var imageSucceeded *voltha.ImageDownload
392 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100393 if cloned.ImageDownloads != nil {
394 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100395 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
396 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
397 imageSucceeded = image
398 index = pos
399 }
400 }
401 }
402
403 if imageSucceeded == nil {
404 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
405 return
406 }
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100407 //update image state on success
Andrea Campanella025667e2021-01-14 11:50:07 +0100408 if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100409 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
Andrea Campanella025667e2021-01-14 11:50:07 +0100410 } else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100411 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100412 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100413 //Enabled is the only state we can go back to.
414 cloned.AdminState = voltha.AdminState_ENABLED
415 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
416 logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
417 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
418 }
419
420}
ssiddiquif076cb82021-04-23 10:47:04 +0530421
422func (agent *Agent) downloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
423 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
424 return nil, err
425 }
426
427 logger.Debugw(ctx, "download-image-to-device", log.Fields{"device-id": agent.deviceID})
428 if agent.device.Root {
429 agent.requestQueue.RequestComplete()
430 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
431 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
432 }
433
434 cloned := agent.cloneDeviceWithoutLock()
435
436 // Send the request to the adapter
437 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
438 defer cancel()
439 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
440
441 ch, err := agent.adapterProxy.DownloadImageToOnuDevice(subCtx, cloned, request)
442 agent.requestQueue.RequestComplete()
443 if err != nil {
444 return nil, err
445 }
446
447 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
448}
449
450func (agent *Agent) getImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
451 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
452 return nil, err
453 }
454
455 cloned := agent.cloneDeviceWithoutLock()
456
457 // Send the request to the adapter
458 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
459 defer cancel()
460 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
461 logger.Debugw(ctx, "get-image-status", log.Fields{"device-id": agent.deviceID})
462
463 ch, err := agent.adapterProxy.GetOnuImageStatus(subCtx, cloned, request)
464 agent.requestQueue.RequestComplete()
465 if err != nil {
466 return nil, err
467 }
468
469 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
470}
471
472func (agent *Agent) activateImageOnDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
473 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
474 return nil, err
475 }
476
477 cloned := agent.cloneDeviceWithoutLock()
478
479 // Send the request to the adapter
480 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
481 defer cancel()
482 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
483 logger.Debugw(ctx, "activate-image-on-device", log.Fields{"device-id": agent.deviceID})
484
485 ch, err := agent.adapterProxy.ActivateOnuImage(subCtx, cloned, request)
486 agent.requestQueue.RequestComplete()
487 if err != nil {
488 return nil, err
489 }
490
491 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
492}
493
494func (agent *Agent) abortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
495 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
496 return nil, err
497 }
498
499 cloned := agent.cloneDeviceWithoutLock()
500
501 // Send the request to the adapter
502 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
503 defer cancel()
504 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
505 logger.Debugw(ctx, "abort-image-on-device", log.Fields{"device-id": agent.deviceID})
506
507 ch, err := agent.adapterProxy.AbortImageUpgrade(subCtx, cloned, request)
508 agent.requestQueue.RequestComplete()
509 if err != nil {
510 return nil, err
511 }
512
513 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
514}
515
516func (agent *Agent) commitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
517 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
518 return nil, err
519 }
520
521 cloned := agent.cloneDeviceWithoutLock()
522
523 // Send the request to the adapter
524 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
525 defer cancel()
526 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
527 logger.Debugw(ctx, "commit-image-on-device", log.Fields{"device-id": agent.deviceID})
528
529 ch, err := agent.adapterProxy.CommitImage(subCtx, cloned, request)
530 agent.requestQueue.RequestComplete()
531 if err != nil {
532 return nil, err
533 }
534
535 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
536}
537
538func (agent *Agent) getOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
539 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
540 return nil, err
541 }
542
543 cloned := agent.cloneDeviceWithoutLock()
544
545 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
546 defer cancel()
547 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
ssiddiqui47348f62021-05-20 20:41:15 +0530548 logger.Debug(ctx, "get-onu-images")
ssiddiquif076cb82021-04-23 10:47:04 +0530549
550 // Send the request to the adapter
551 ch, err := agent.adapterProxy.GetOnuImages(subCtx, cloned, id)
552 agent.requestQueue.RequestComplete()
553 if err != nil {
554 return nil, err
555 }
556
557 //wait for adapter response
558 select {
559 case rpcResponse, ok := <-ch:
560 if !ok {
561 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
562 } else if rpcResponse.Err != nil {
563 // return error
564 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
565 } else {
566 resp := &voltha.OnuImages{}
567 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
568 return nil, status.Errorf(codes.Internal, "%s", err.Error())
569 }
570
571 return resp, nil
572 }
573 case <-ctx.Done():
574 return nil, ctx.Err()
575 }
576}
577
578func (agent *Agent) getDeviceImageResponseFromAdapter(ctx context.Context, ch chan *kafka.RpcResponse) (*voltha.DeviceImageResponse, error) {
579 //wait for adapter response
580 select {
581 case rpcResponse, ok := <-ch:
582 if !ok {
583 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
584 } else if rpcResponse.Err != nil {
585 // return error
586 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
587 } else {
588 resp := &voltha.DeviceImageResponse{}
589 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
590 return nil, status.Errorf(codes.Internal, "%s", err.Error())
591 }
592
593 if len(resp.DeviceImageStates) == 0 || resp.DeviceImageStates[0] == nil {
594 return nil, status.Errorf(codes.Internal, "invalid response from adapter")
595 }
596
597 return resp, nil
598 }
599 case <-ctx.Done():
600 return nil, ctx.Err()
601 }
602}