blob: 37815406913dce12288391d9dea83458a94a0e54 [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 {
41 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
42 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070043 }
Andrea Campanella025667e2021-01-14 11:50:07 +010044
45 device := agent.cloneDeviceWithoutLock()
46 if device.ImageDownloads != nil {
47 for _, image := range device.ImageDownloads {
48 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
49 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, already downloading image:%s",
50 agent.deviceID, image.Name)
51 }
52 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040053 }
54
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070055 // Save the image
56 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
57 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermanf6db9f12020-07-22 17:16:19 -040058 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanellac05c4c42021-02-11 10:25:28 +010059 _, index, err := getImage(img, device)
60 if err != nil {
61 cloned.ImageDownloads = append(device.ImageDownloads, clonedImg)
62 } else {
63 cloned.ImageDownloads[index] = clonedImg
64 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070065
Kent Hagermanf6db9f12020-07-22 17:16:19 -040066 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
67 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
68 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070069 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040070
71 // Send the request to the adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +000072 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +053073 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
74
Andrea Campanella025667e2021-01-14 11:50:07 +010075 ch, err := agent.adapterProxy.DownloadImage(subCtx, cloned, clonedImg)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040076 if err != nil {
77 cancel()
78 return nil, err
79 }
Andrea Campanella025667e2021-01-14 11:50:07 +010080 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onImageSuccess, agent.onImageFailure)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040081
Andrea Campanella025667e2021-01-14 11:50:07 +010082 return &common.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070083}
84
Andrea Campanella025667e2021-01-14 11:50:07 +010085// getImage is a helper method to figure out if an image is already registered
86func getImage(img *voltha.ImageDownload, device *voltha.Device) (*voltha.ImageDownload, int, error) {
87 for pos, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070088 if image.Id == img.Id && image.Name == img.Name {
Andrea Campanella025667e2021-01-14 11:50:07 +010089 return image, pos, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070090 }
91 }
Andrea Campanella025667e2021-01-14 11:50:07 +010092 return nil, -1, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s",
93 device.Id, img.Name)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070094}
95
Andrea Campanella025667e2021-01-14 11:50:07 +010096func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070097 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
98 return nil, err
99 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530100 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700101
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700102 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400103 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100104 _, index, err := getImage(img, cloned)
105 if err != nil {
106 agent.requestQueue.RequestComplete()
107 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700108 }
109
Andrea Campanella025667e2021-01-14 11:50:07 +0100110 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
111
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400112 if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
113 agent.requestQueue.RequestComplete()
114 } else {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700115 // Set the device to Enabled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400116 cloned.AdminState = voltha.AdminState_ENABLED
117 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700118 return nil, err
119 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000120 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530121 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
122
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400123 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700124 if err != nil {
125 cancel()
126 return nil, err
127 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100128 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onImageSuccess,
129 agent.onImageFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700130 }
131 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
132}
133
134func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
135 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
136 return nil, err
137 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530138 logger.Debugw(ctx, "activate-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700139
Andrea Campanella025667e2021-01-14 11:50:07 +0100140 // Update image download state
141 cloned := agent.cloneDeviceWithoutLock()
142 image, index, err := getImage(img, cloned)
143 if err != nil {
144 agent.requestQueue.RequestComplete()
145 return nil, err
146 }
147
Andrea Campanella025667e2021-01-14 11:50:07 +0100148 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
149 agent.requestQueue.RequestComplete()
150 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-has-not-downloaded-image:%s", agent.deviceID, img.Name)
151 }
152
153 //TODO does this need to be removed ?
154 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400155 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700156 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
157 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400158
Andrea Campanella025667e2021-01-14 11:50:07 +0100159 // Save the image
160 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
161
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400162 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
163 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700164 return nil, err
165 }
166
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000167 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530168 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
169
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400170 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700171 if err != nil {
172 cancel()
173 return nil, err
174 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100175 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onImageSuccess, agent.onFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700176
177 // The status of the AdminState will be changed following the update_download_status response from the adapter
178 // The image name will also be removed from the device list
179 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
180}
181
182func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
183 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
184 return nil, err
185 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530186 logger.Debugw(ctx, "revert-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700187
Andrea Campanella025667e2021-01-14 11:50:07 +0100188 // Update image download state
189 cloned := agent.cloneDeviceWithoutLock()
190 _, index, err := getImage(img, cloned)
191 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400192 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700193 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
194 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100195 if cloned.AdminState != voltha.AdminState_ENABLED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400196 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700197 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
198 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100199
200 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_REVERTING
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700201
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400202 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700203 return nil, err
204 }
205
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000206 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530207 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
208
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400209 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700210 if err != nil {
211 cancel()
212 return nil, err
213 }
214 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
215
216 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
217}
218
219func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530220 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700221
222 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
223 return nil, err
224 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400225 device := agent.getDeviceReadOnlyWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700226 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
227 agent.requestQueue.RequestComplete()
228 if err != nil {
229 return nil, err
230 }
231 // Wait for the adapter response
232 rpcResponse, ok := <-ch
233 if !ok {
234 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
235 }
236 if rpcResponse.Err != nil {
237 return nil, rpcResponse.Err
238 }
239 // Successful response
240 imgDownload := &voltha.ImageDownload{}
241 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
242 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
243 }
244 return imgDownload, nil
245}
246
247func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
248 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
249 return err
250 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000251 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700252
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700253 // Update the image as well as remove it if the download was cancelled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400254 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700255 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
256 for _, image := range cloned.ImageDownloads {
257 if image.Id == img.Id && image.Name == img.Name {
258 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
259 clonedImages = append(clonedImages, img)
260 }
261 }
262 }
263 cloned.ImageDownloads = clonedImages
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400264
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700265 // Set the Admin state to enabled if required
266 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
267 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400268 img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
269 cloned.AdminState = voltha.AdminState_ENABLED
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700270 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400271 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700272}
273
274func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530275 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700276
Kent Hagermancba2f302020-07-28 13:37:36 -0400277 device, err := agent.getDeviceReadOnly(ctx)
278 if err != nil {
279 return nil, status.Errorf(codes.Aborted, "%s", err)
280 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400281 for _, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700282 if image.Id == img.Id && image.Name == img.Name {
283 return image, nil
284 }
285 }
286 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
287}
288
289func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530290 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700291
Kent Hagermancba2f302020-07-28 13:37:36 -0400292 device, err := agent.getDeviceReadOnly(ctx)
293 if err != nil {
294 return nil, status.Errorf(codes.Aborted, "%s", err)
295 }
296 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700297}
Andrea Campanella025667e2021-01-14 11:50:07 +0100298
299// onImageFailure brings back the device to Enabled state and sets the image to image download_failed.
300func (agent *Agent) onImageFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100301 // original context has failed due to timeout , let's open a new one
302 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
303 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
304
305 if err := agent.requestQueue.WaitForGreenLight(subCtx); err != nil {
306 logger.Errorw(subCtx, "can't obtain lock", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": err, "args": reqArgs})
307 cancel()
Andrea Campanella025667e2021-01-14 11:50:07 +0100308 return
309 }
310 if res, ok := response.(error); ok {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100311 logger.Errorw(subCtx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
312 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100313 //TODO base this on IMAGE ID when created
314 var imageFailed *voltha.ImageDownload
315 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100316 if cloned.ImageDownloads != nil {
317 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100318 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
319 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
320 imageFailed = image
321 index = pos
322 }
323 }
324 }
325
326 if imageFailed == nil {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100327 logger.Errorw(subCtx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
328 cancel()
Andrea Campanella025667e2021-01-14 11:50:07 +0100329 return
330 }
331
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100332 //update image state on failure
Andrea Campanella025667e2021-01-14 11:50:07 +0100333 if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100334 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
Andrea Campanella025667e2021-01-14 11:50:07 +0100335 } else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100336 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_INACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100337 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100338 //Enabled is the only state we can go back to.
339 cloned.AdminState = voltha.AdminState_ENABLED
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100340 if err := agent.updateDeviceAndReleaseLock(subCtx, cloned); err != nil {
341 logger.Errorw(subCtx, "failed-enable-device-after-image-failure",
Andrea Campanella025667e2021-01-14 11:50:07 +0100342 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
343 }
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100344 cancel()
Andrea Campanella025667e2021-01-14 11:50:07 +0100345 } else {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100346 logger.Errorw(subCtx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
347 cancel()
348 return
Andrea Campanella025667e2021-01-14 11:50:07 +0100349 }
350 // TODO: Post failure message onto kafka
351}
352
353// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
354func (agent *Agent) onImageSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
355 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530356 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 +0100357 return
358 }
Matteo Scandolo03686da2021-03-09 13:16:55 -0800359 logger.Infow(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100360 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100361 //TODO base this on IMAGE ID when created
362 var imageSucceeded *voltha.ImageDownload
363 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100364 if cloned.ImageDownloads != nil {
365 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100366 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
367 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
368 imageSucceeded = image
369 index = pos
370 }
371 }
372 }
373
374 if imageSucceeded == nil {
375 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
376 return
377 }
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100378 //update image state on success
Andrea Campanella025667e2021-01-14 11:50:07 +0100379 if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100380 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
Andrea Campanella025667e2021-01-14 11:50:07 +0100381 } else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100382 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100383 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100384 //Enabled is the only state we can go back to.
385 cloned.AdminState = voltha.AdminState_ENABLED
386 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
387 logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
388 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
389 }
390
391}
ssiddiquif076cb82021-04-23 10:47:04 +0530392
393func (agent *Agent) downloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
394 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
395 return nil, err
396 }
397
398 logger.Debugw(ctx, "download-image-to-device", log.Fields{"device-id": agent.deviceID})
399 if agent.device.Root {
400 agent.requestQueue.RequestComplete()
401 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
402 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
403 }
404
405 cloned := agent.cloneDeviceWithoutLock()
406
407 // Send the request to the adapter
408 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
409 defer cancel()
410 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
411
412 ch, err := agent.adapterProxy.DownloadImageToOnuDevice(subCtx, cloned, request)
413 agent.requestQueue.RequestComplete()
414 if err != nil {
415 return nil, err
416 }
417
418 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
419}
420
421func (agent *Agent) getImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
422 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
423 return nil, err
424 }
425
426 cloned := agent.cloneDeviceWithoutLock()
427
428 // Send the request to the adapter
429 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
430 defer cancel()
431 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
432 logger.Debugw(ctx, "get-image-status", log.Fields{"device-id": agent.deviceID})
433
434 ch, err := agent.adapterProxy.GetOnuImageStatus(subCtx, cloned, request)
435 agent.requestQueue.RequestComplete()
436 if err != nil {
437 return nil, err
438 }
439
440 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
441}
442
443func (agent *Agent) activateImageOnDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
444 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
445 return nil, err
446 }
447
448 cloned := agent.cloneDeviceWithoutLock()
449
450 // Send the request to the adapter
451 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
452 defer cancel()
453 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
454 logger.Debugw(ctx, "activate-image-on-device", log.Fields{"device-id": agent.deviceID})
455
456 ch, err := agent.adapterProxy.ActivateOnuImage(subCtx, cloned, request)
457 agent.requestQueue.RequestComplete()
458 if err != nil {
459 return nil, err
460 }
461
462 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
463}
464
465func (agent *Agent) abortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
466 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
467 return nil, err
468 }
469
470 cloned := agent.cloneDeviceWithoutLock()
471
472 // Send the request to the adapter
473 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
474 defer cancel()
475 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
476 logger.Debugw(ctx, "abort-image-on-device", log.Fields{"device-id": agent.deviceID})
477
478 ch, err := agent.adapterProxy.AbortImageUpgrade(subCtx, cloned, request)
479 agent.requestQueue.RequestComplete()
480 if err != nil {
481 return nil, err
482 }
483
484 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
485}
486
487func (agent *Agent) commitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
488 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
489 return nil, err
490 }
491
492 cloned := agent.cloneDeviceWithoutLock()
493
494 // Send the request to the adapter
495 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
496 defer cancel()
497 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
498 logger.Debugw(ctx, "commit-image-on-device", log.Fields{"device-id": agent.deviceID})
499
500 ch, err := agent.adapterProxy.CommitImage(subCtx, cloned, request)
501 agent.requestQueue.RequestComplete()
502 if err != nil {
503 return nil, err
504 }
505
506 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
507}
508
509func (agent *Agent) getOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
510 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
511 return nil, err
512 }
513
514 cloned := agent.cloneDeviceWithoutLock()
515
516 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
517 defer cancel()
518 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
519 logger.Debugw(ctx, "get-onu-images", log.Fields{"device-id": agent.deviceID})
520
521 // Send the request to the adapter
522 ch, err := agent.adapterProxy.GetOnuImages(subCtx, cloned, id)
523 agent.requestQueue.RequestComplete()
524 if err != nil {
525 return nil, err
526 }
527
528 //wait for adapter response
529 select {
530 case rpcResponse, ok := <-ch:
531 if !ok {
532 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
533 } else if rpcResponse.Err != nil {
534 // return error
535 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
536 } else {
537 resp := &voltha.OnuImages{}
538 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
539 return nil, status.Errorf(codes.Internal, "%s", err.Error())
540 }
541
542 return resp, nil
543 }
544 case <-ctx.Done():
545 return nil, ctx.Err()
546 }
547}
548
549func (agent *Agent) getDeviceImageResponseFromAdapter(ctx context.Context, ch chan *kafka.RpcResponse) (*voltha.DeviceImageResponse, error) {
550 //wait for adapter response
551 select {
552 case rpcResponse, ok := <-ch:
553 if !ok {
554 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
555 } else if rpcResponse.Err != nil {
556 // return error
557 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
558 } else {
559 resp := &voltha.DeviceImageResponse{}
560 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
561 return nil, status.Errorf(codes.Internal, "%s", err.Error())
562 }
563
564 if len(resp.DeviceImageStates) == 0 || resp.DeviceImageStates[0] == nil {
565 return nil, status.Errorf(codes.Internal, "invalid response from adapter")
566 }
567
568 return resp, nil
569 }
570 case <-ctx.Done():
571 return nil, ctx.Err()
572 }
573}