blob: e71af8a82a4478e878635a4cb3e0509cbbabf4b3 [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
yasin sapli5458a1c2021-06-14 22:24:38 +000022 "github.com/opencord/voltha-lib-go/v5/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"
yasin sapli5458a1c2021-06-14 22:24:38 +000028 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Maninderdfadc982020-10-28 14:04:33 +053029 "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 }
Maninder2195ccc2021-06-23 20:23:01 +053045
46 device := agent.cloneDeviceWithoutLock()
47
48 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +053049 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +053050 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as device deletion is in progress or reconciling is in progress/failed.",
Maninder0aabf0c2021-03-17 14:55:14 +053051 agent.deviceID)
52 }
Andrea Campanella025667e2021-01-14 11:50:07 +010053
Andrea Campanella025667e2021-01-14 11:50:07 +010054 if device.ImageDownloads != nil {
55 for _, image := range device.ImageDownloads {
56 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
57 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, already downloading image:%s",
58 agent.deviceID, image.Name)
59 }
60 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040061 }
62
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070063 // Save the image
64 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
65 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermanf6db9f12020-07-22 17:16:19 -040066 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanellac05c4c42021-02-11 10:25:28 +010067 _, index, err := getImage(img, device)
68 if err != nil {
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030069 cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
Andrea Campanellac05c4c42021-02-11 10:25:28 +010070 } else {
71 cloned.ImageDownloads[index] = clonedImg
72 }
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070073
Kent Hagermanf6db9f12020-07-22 17:16:19 -040074 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
75 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
76 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070077 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040078
79 // Send the request to the adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +000080 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +053081 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
82
Andrea Campanella025667e2021-01-14 11:50:07 +010083 ch, err := agent.adapterProxy.DownloadImage(subCtx, cloned, clonedImg)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040084 if err != nil {
85 cancel()
86 return nil, err
87 }
Andrea Campanella025667e2021-01-14 11:50:07 +010088 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onImageSuccess, agent.onImageFailure)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040089
Andrea Campanella025667e2021-01-14 11:50:07 +010090 return &common.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070091}
92
Andrea Campanella025667e2021-01-14 11:50:07 +010093// getImage is a helper method to figure out if an image is already registered
94func getImage(img *voltha.ImageDownload, device *voltha.Device) (*voltha.ImageDownload, int, error) {
95 for pos, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070096 if image.Id == img.Id && image.Name == img.Name {
Andrea Campanella025667e2021-01-14 11:50:07 +010097 return image, pos, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070098 }
99 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100100 return nil, -1, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s",
101 device.Id, img.Name)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700102}
103
Andrea Campanella025667e2021-01-14 11:50:07 +0100104func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700105 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
106 return nil, err
107 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530108 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700109
Maninder2195ccc2021-06-23 20:23:01 +0530110 cloned := agent.cloneDeviceWithoutLock()
111
112 if !agent.proceedWithRequest(cloned) {
Maninder0aabf0c2021-03-17 14:55:14 +0530113 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +0530114 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as device deletion is in progress or reconciling is in progress/failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530115 agent.deviceID)
116 }
117
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700118 // Update image download state
Andrea Campanella025667e2021-01-14 11:50:07 +0100119 _, index, err := getImage(img, cloned)
120 if err != nil {
121 agent.requestQueue.RequestComplete()
122 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700123 }
124
Andrea Campanella025667e2021-01-14 11:50:07 +0100125 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
126
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400127 if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
128 agent.requestQueue.RequestComplete()
129 } else {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700130 // Set the device to Enabled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400131 cloned.AdminState = voltha.AdminState_ENABLED
132 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700133 return nil, err
134 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000135 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530136 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
137
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400138 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700139 if err != nil {
140 cancel()
141 return nil, err
142 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100143 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onImageSuccess,
144 agent.onImageFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700145 }
146 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
147}
148
149func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
150 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
151 return nil, err
152 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530153 logger.Debugw(ctx, "activate-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700154
Maninder2195ccc2021-06-23 20:23:01 +0530155 cloned := agent.cloneDeviceWithoutLock()
156
157 if !agent.proceedWithRequest(cloned) {
Maninder0aabf0c2021-03-17 14:55:14 +0530158 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +0530159 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as device deletion is in progress or reconcile is in progress/failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530160 agent.deviceID)
161 }
162
Andrea Campanella025667e2021-01-14 11:50:07 +0100163 // Update image download state
Andrea Campanella025667e2021-01-14 11:50:07 +0100164 image, index, err := getImage(img, cloned)
165 if err != nil {
166 agent.requestQueue.RequestComplete()
167 return nil, err
168 }
169
Andrea Campanella025667e2021-01-14 11:50:07 +0100170 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
171 agent.requestQueue.RequestComplete()
172 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-has-not-downloaded-image:%s", agent.deviceID, img.Name)
173 }
174
175 //TODO does this need to be removed ?
176 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400177 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700178 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
179 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400180
Andrea Campanella025667e2021-01-14 11:50:07 +0100181 // Save the image
182 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
183
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400184 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
185 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700186 return nil, err
187 }
188
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000189 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530190 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
191
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400192 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700193 if err != nil {
194 cancel()
195 return nil, err
196 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100197 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onImageSuccess, agent.onFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700198
199 // The status of the AdminState will be changed following the update_download_status response from the adapter
200 // The image name will also be removed from the device list
201 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
202}
203
204func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
205 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
206 return nil, err
207 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530208 logger.Debugw(ctx, "revert-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700209
Andrea Campanella025667e2021-01-14 11:50:07 +0100210 // Update image download state
211 cloned := agent.cloneDeviceWithoutLock()
212 _, index, err := getImage(img, cloned)
213 if err != nil {
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, image-not-registered:%s", agent.deviceID, img.Name)
216 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100217 if cloned.AdminState != voltha.AdminState_ENABLED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400218 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700219 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
220 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100221
222 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_REVERTING
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700223
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400224 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700225 return nil, err
226 }
227
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000228 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530229 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
230
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400231 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700232 if err != nil {
233 cancel()
234 return nil, err
235 }
236 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
237
238 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
239}
240
241func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530242 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700243
244 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
245 return nil, err
246 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400247 device := agent.getDeviceReadOnlyWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700248 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
249 agent.requestQueue.RequestComplete()
250 if err != nil {
251 return nil, err
252 }
253 // Wait for the adapter response
254 rpcResponse, ok := <-ch
255 if !ok {
256 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
257 }
258 if rpcResponse.Err != nil {
259 return nil, rpcResponse.Err
260 }
261 // Successful response
262 imgDownload := &voltha.ImageDownload{}
263 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
264 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
265 }
266 return imgDownload, nil
267}
268
269func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
270 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
271 return err
272 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000273 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700274
Maninder2195ccc2021-06-23 20:23:01 +0530275 cloned := agent.cloneDeviceWithoutLock()
276
277 if !agent.proceedWithRequest(cloned) {
Maninder0aabf0c2021-03-17 14:55:14 +0530278 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +0530279 return status.Errorf(codes.FailedPrecondition, "deviceId:%s, Cannot complete operation as device deletion is in progress or reconciling is in progress/failed.",
Maninder0aabf0c2021-03-17 14:55:14 +0530280 agent.deviceID)
281 }
282
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700283 // Update the image as well as remove it if the download was cancelled
284 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
285 for _, image := range cloned.ImageDownloads {
286 if image.Id == img.Id && image.Name == img.Name {
287 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
288 clonedImages = append(clonedImages, img)
289 }
290 }
291 }
292 cloned.ImageDownloads = clonedImages
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400293
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700294 // Set the Admin state to enabled if required
295 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
296 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400297 img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
298 cloned.AdminState = voltha.AdminState_ENABLED
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700299 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400300 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700301}
302
303func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530304 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700305
Kent Hagermancba2f302020-07-28 13:37:36 -0400306 device, err := agent.getDeviceReadOnly(ctx)
307 if err != nil {
308 return nil, status.Errorf(codes.Aborted, "%s", err)
309 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400310 for _, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700311 if image.Id == img.Id && image.Name == img.Name {
312 return image, nil
313 }
314 }
315 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
316}
317
318func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530319 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700320
Kent Hagermancba2f302020-07-28 13:37:36 -0400321 device, err := agent.getDeviceReadOnly(ctx)
322 if err != nil {
323 return nil, status.Errorf(codes.Aborted, "%s", err)
324 }
325 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700326}
Andrea Campanella025667e2021-01-14 11:50:07 +0100327
328// onImageFailure brings back the device to Enabled state and sets the image to image download_failed.
329func (agent *Agent) onImageFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100330 // original context has failed due to timeout , let's open a new one
331 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
332 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
Maninder0aabf0c2021-03-17 14:55:14 +0530333 defer cancel()
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100334
335 if err := agent.requestQueue.WaitForGreenLight(subCtx); err != nil {
336 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 +0530337 return
338 }
Maninder2195ccc2021-06-23 20:23:01 +0530339
340 device := agent.getDeviceReadOnlyWithoutLock()
341
342 if !agent.proceedWithRequest(device) {
Maninder0aabf0c2021-03-17 14:55:14 +0530343 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +0530344 logger.Errorw(subCtx, "Cannot complete operation as device deletion is in progress or reconciling is in progress/failed.",
Maninder581cf4b2021-06-16 22:42:07 +0530345 log.Fields{"rpc": rpc, "device-id": agent.deviceID})
Andrea Campanella025667e2021-01-14 11:50:07 +0100346 return
347 }
348 if res, ok := response.(error); ok {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100349 logger.Errorw(subCtx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
350 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +0100351 //TODO base this on IMAGE ID when created
352 var imageFailed *voltha.ImageDownload
353 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100354 if cloned.ImageDownloads != nil {
355 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100356 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
357 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
358 imageFailed = image
359 index = pos
360 }
361 }
362 }
363
364 if imageFailed == nil {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100365 logger.Errorw(subCtx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanella025667e2021-01-14 11:50:07 +0100366 return
367 }
368
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100369 //update image state on failure
Andrea Campanella025667e2021-01-14 11:50:07 +0100370 if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100371 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
Andrea Campanella025667e2021-01-14 11:50:07 +0100372 } else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100373 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_INACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100374 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100375 //Enabled is the only state we can go back to.
376 cloned.AdminState = voltha.AdminState_ENABLED
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100377 if err := agent.updateDeviceAndReleaseLock(subCtx, cloned); err != nil {
378 logger.Errorw(subCtx, "failed-enable-device-after-image-failure",
Andrea Campanella025667e2021-01-14 11:50:07 +0100379 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
380 }
381 } else {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100382 logger.Errorw(subCtx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100383 return
Andrea Campanella025667e2021-01-14 11:50:07 +0100384 }
385 // TODO: Post failure message onto kafka
386}
387
388// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
389func (agent *Agent) onImageSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
390 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530391 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 +0100392 return
393 }
Maninder2195ccc2021-06-23 20:23:01 +0530394
395 cloned := agent.cloneDeviceWithoutLock()
396
397 if !agent.proceedWithRequest(cloned) {
Maninder0aabf0c2021-03-17 14:55:14 +0530398 agent.requestQueue.RequestComplete()
Maninder2195ccc2021-06-23 20:23:01 +0530399 logger.Errorw(ctx, "Cannot complete operation as Device deletion is in progress or reconciling is in progress/failed.",
Maninder581cf4b2021-06-16 22:42:07 +0530400 log.Fields{"rpc": rpc, "device-id": agent.deviceID})
Maninder0aabf0c2021-03-17 14:55:14 +0530401 return
402 }
Matteo Scandolo03686da2021-03-09 13:16:55 -0800403 logger.Infow(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
Maninder2195ccc2021-06-23 20:23:01 +0530404
Andrea Campanella025667e2021-01-14 11:50:07 +0100405 //TODO base this on IMAGE ID when created
406 var imageSucceeded *voltha.ImageDownload
407 var index int
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100408 if cloned.ImageDownloads != nil {
409 for pos, image := range cloned.ImageDownloads {
Andrea Campanella025667e2021-01-14 11:50:07 +0100410 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
411 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
412 imageSucceeded = image
413 index = pos
414 }
415 }
416 }
417
418 if imageSucceeded == nil {
419 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
420 return
421 }
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100422 //update image state on success
Andrea Campanella025667e2021-01-14 11:50:07 +0100423 if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100424 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
Andrea Campanella025667e2021-01-14 11:50:07 +0100425 } else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
Andrea Campanellac05c4c42021-02-11 10:25:28 +0100426 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVE
Andrea Campanella025667e2021-01-14 11:50:07 +0100427 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100428 //Enabled is the only state we can go back to.
429 cloned.AdminState = voltha.AdminState_ENABLED
430 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
431 logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
432 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
433 }
434
435}
ssiddiquif076cb82021-04-23 10:47:04 +0530436
437func (agent *Agent) downloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
438 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
439 return nil, err
440 }
441
442 logger.Debugw(ctx, "download-image-to-device", log.Fields{"device-id": agent.deviceID})
443 if agent.device.Root {
444 agent.requestQueue.RequestComplete()
445 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
446 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
447 }
448
449 cloned := agent.cloneDeviceWithoutLock()
450
451 // Send the request to the adapter
452 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
453 defer cancel()
454 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
455
456 ch, err := agent.adapterProxy.DownloadImageToOnuDevice(subCtx, cloned, request)
457 agent.requestQueue.RequestComplete()
458 if err != nil {
459 return nil, err
460 }
461
462 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
463}
464
465func (agent *Agent) getImageStatus(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, "get-image-status", log.Fields{"device-id": agent.deviceID})
477
478 ch, err := agent.adapterProxy.GetOnuImageStatus(subCtx, cloned, request)
479 agent.requestQueue.RequestComplete()
480 if err != nil {
481 return nil, err
482 }
483
484 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
485}
486
487func (agent *Agent) activateImageOnDevice(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, "activate-image-on-device", log.Fields{"device-id": agent.deviceID})
499
500 ch, err := agent.adapterProxy.ActivateOnuImage(subCtx, cloned, request)
501 agent.requestQueue.RequestComplete()
502 if err != nil {
503 return nil, err
504 }
505
506 return agent.getDeviceImageResponseFromAdapter(subCtx, ch)
507}
508
509func (agent *Agent) abortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
510 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
511 return nil, err
512 }
513
514 cloned := agent.cloneDeviceWithoutLock()
515
516 // Send the request to the adapter
517 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
518 defer cancel()
519 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
520 logger.Debugw(ctx, "abort-image-on-device", log.Fields{"device-id": agent.deviceID})
521
522 ch, err := agent.adapterProxy.AbortImageUpgrade(subCtx, cloned, request)
523 agent.requestQueue.RequestComplete()
524 if err != nil {
525 return nil, err
526 }
527
528 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
529}
530
531func (agent *Agent) commitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
532 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
533 return nil, err
534 }
535
536 cloned := agent.cloneDeviceWithoutLock()
537
538 // Send the request to the adapter
539 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
540 defer cancel()
541 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
542 logger.Debugw(ctx, "commit-image-on-device", log.Fields{"device-id": agent.deviceID})
543
544 ch, err := agent.adapterProxy.CommitImage(subCtx, cloned, request)
545 agent.requestQueue.RequestComplete()
546 if err != nil {
547 return nil, err
548 }
549
550 return agent.getDeviceImageResponseFromAdapter(ctx, ch)
551}
552
553func (agent *Agent) getOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
554 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
555 return nil, err
556 }
557
558 cloned := agent.cloneDeviceWithoutLock()
559
560 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
561 defer cancel()
562 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
ssiddiqui47348f62021-05-20 20:41:15 +0530563 logger.Debug(ctx, "get-onu-images")
ssiddiquif076cb82021-04-23 10:47:04 +0530564
565 // Send the request to the adapter
566 ch, err := agent.adapterProxy.GetOnuImages(subCtx, cloned, id)
567 agent.requestQueue.RequestComplete()
568 if err != nil {
569 return nil, err
570 }
571
572 //wait for adapter response
573 select {
574 case rpcResponse, ok := <-ch:
575 if !ok {
576 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
577 } else if rpcResponse.Err != nil {
578 // return error
579 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
580 } else {
581 resp := &voltha.OnuImages{}
582 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
583 return nil, status.Errorf(codes.Internal, "%s", err.Error())
584 }
585
586 return resp, nil
587 }
588 case <-ctx.Done():
589 return nil, ctx.Err()
590 }
591}
592
593func (agent *Agent) getDeviceImageResponseFromAdapter(ctx context.Context, ch chan *kafka.RpcResponse) (*voltha.DeviceImageResponse, error) {
594 //wait for adapter response
595 select {
596 case rpcResponse, ok := <-ch:
597 if !ok {
598 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
599 } else if rpcResponse.Err != nil {
600 // return error
601 return nil, status.Errorf(codes.Internal, "%s", rpcResponse.Err.Error())
602 } else {
603 resp := &voltha.DeviceImageResponse{}
604 if err := ptypes.UnmarshalAny(rpcResponse.Reply, resp); err != nil {
605 return nil, status.Errorf(codes.Internal, "%s", err.Error())
606 }
607
608 if len(resp.DeviceImageStates) == 0 || resp.DeviceImageStates[0] == nil {
609 return nil, status.Errorf(codes.Internal, "invalid response from adapter")
610 }
611
612 return resp, nil
613 }
614 case <-ctx.Done():
615 return nil, ctx.Err()
616 }
617}