blob: eed1879ed6172c81880616009a69682f573f6a9d [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"
Andrea Campanella025667e2021-01-14 11:50:07 +010021 "github.com/opencord/voltha-protos/v4/go/common"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070022
23 "github.com/gogo/protobuf/proto"
24 "github.com/golang/protobuf/ptypes"
Himani Chawlab4c25912020-11-12 17:16:38 +053025 coreutils "github.com/opencord/voltha-go/rw_core/utils"
Maninderdfadc982020-10-28 14:04:33 +053026 "github.com/opencord/voltha-lib-go/v4/pkg/log"
27 "github.com/opencord/voltha-protos/v4/go/voltha"
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
Andrea Campanella025667e2021-01-14 11:50:07 +010032func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070033 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
34 return nil, err
35 }
Himani Chawlab4c25912020-11-12 17:16:38 +053036 logger.Debugw(ctx, "download-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070037
Andrea Campanella025667e2021-01-14 11:50:07 +010038 if agent.device.Root {
39 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
40 "not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070041 }
Andrea Campanella025667e2021-01-14 11:50:07 +010042
43 device := agent.cloneDeviceWithoutLock()
44 if device.ImageDownloads != nil {
45 for _, image := range device.ImageDownloads {
46 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
47 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, already downloading image:%s",
48 agent.deviceID, image.Name)
49 }
50 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040051 }
52
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070053 // Save the image
54 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
55 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermanf6db9f12020-07-22 17:16:19 -040056 cloned := agent.cloneDeviceWithoutLock()
57 cloned.ImageDownloads = append(device.ImageDownloads, clonedImg)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070058
Kent Hagermanf6db9f12020-07-22 17:16:19 -040059 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
60 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
61 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070062 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040063
64 // Send the request to the adapter
Rohan Agrawalcf12f202020-08-03 04:42:01 +000065 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +053066 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
67
Andrea Campanella025667e2021-01-14 11:50:07 +010068 ch, err := agent.adapterProxy.DownloadImage(subCtx, cloned, clonedImg)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040069 if err != nil {
70 cancel()
71 return nil, err
72 }
Andrea Campanella025667e2021-01-14 11:50:07 +010073 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onImageSuccess, agent.onImageFailure)
Kent Hagermanf6db9f12020-07-22 17:16:19 -040074
Andrea Campanella025667e2021-01-14 11:50:07 +010075 return &common.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070076}
77
Andrea Campanella025667e2021-01-14 11:50:07 +010078// getImage is a helper method to figure out if an image is already registered
79func getImage(img *voltha.ImageDownload, device *voltha.Device) (*voltha.ImageDownload, int, error) {
80 for pos, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070081 if image.Id == img.Id && image.Name == img.Name {
Andrea Campanella025667e2021-01-14 11:50:07 +010082 return image, pos, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070083 }
84 }
Andrea Campanella025667e2021-01-14 11:50:07 +010085 return nil, -1, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s",
86 device.Id, img.Name)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070087}
88
Andrea Campanella025667e2021-01-14 11:50:07 +010089func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070090 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
91 return nil, err
92 }
Himani Chawlab4c25912020-11-12 17:16:38 +053093 logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070094
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070095 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -040096 cloned := agent.cloneDeviceWithoutLock()
Andrea Campanella025667e2021-01-14 11:50:07 +010097 _, index, err := getImage(img, cloned)
98 if err != nil {
99 agent.requestQueue.RequestComplete()
100 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700101 }
102
Andrea Campanella025667e2021-01-14 11:50:07 +0100103 cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
104
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400105 if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
106 agent.requestQueue.RequestComplete()
107 } else {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700108 // Set the device to Enabled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400109 cloned.AdminState = voltha.AdminState_ENABLED
110 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700111 return nil, err
112 }
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000113 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530114 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
115
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400116 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700117 if err != nil {
118 cancel()
119 return nil, err
120 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100121 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onImageSuccess,
122 agent.onImageFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700123 }
124 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
125}
126
127func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
128 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
129 return nil, err
130 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530131 logger.Debugw(ctx, "activate-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700132
Andrea Campanella025667e2021-01-14 11:50:07 +0100133 // Update image download state
134 cloned := agent.cloneDeviceWithoutLock()
135 image, index, err := getImage(img, cloned)
136 if err != nil {
137 agent.requestQueue.RequestComplete()
138 return nil, err
139 }
140
141 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400142 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700143 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
144 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100145
146 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
147 agent.requestQueue.RequestComplete()
148 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-has-not-downloaded-image:%s", agent.deviceID, img.Name)
149 }
150
151 //TODO does this need to be removed ?
152 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400153 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700154 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
155 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400156
Andrea Campanella025667e2021-01-14 11:50:07 +0100157 // Save the image
158 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
159
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400160 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
161 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700162 return nil, err
163 }
164
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000165 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530166 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
167
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400168 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700169 if err != nil {
170 cancel()
171 return nil, err
172 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100173 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onImageSuccess, agent.onFailure)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700174
175 // The status of the AdminState will be changed following the update_download_status response from the adapter
176 // The image name will also be removed from the device list
177 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
178}
179
180func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
181 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
182 return nil, err
183 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530184 logger.Debugw(ctx, "revert-image", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700185
Andrea Campanella025667e2021-01-14 11:50:07 +0100186 // Update image download state
187 cloned := agent.cloneDeviceWithoutLock()
188 _, index, err := getImage(img, cloned)
189 if err != nil {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400190 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700191 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
192 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100193 if cloned.AdminState != voltha.AdminState_ENABLED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400194 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700195 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
196 }
Andrea Campanella025667e2021-01-14 11:50:07 +0100197
198 cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_REVERTING
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700199
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400200 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700201 return nil, err
202 }
203
Rohan Agrawalcf12f202020-08-03 04:42:01 +0000204 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.defaultTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530205 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
206
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400207 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700208 if err != nil {
209 cancel()
210 return nil, err
211 }
212 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
213
214 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
215}
216
217func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530218 logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700219
220 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
221 return nil, err
222 }
Kent Hagermancba2f302020-07-28 13:37:36 -0400223 device := agent.getDeviceReadOnlyWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700224 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
225 agent.requestQueue.RequestComplete()
226 if err != nil {
227 return nil, err
228 }
229 // Wait for the adapter response
230 rpcResponse, ok := <-ch
231 if !ok {
232 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
233 }
234 if rpcResponse.Err != nil {
235 return nil, rpcResponse.Err
236 }
237 // Successful response
238 imgDownload := &voltha.ImageDownload{}
239 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
240 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
241 }
242 return imgDownload, nil
243}
244
245func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
246 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
247 return err
248 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000249 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700250
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700251 // Update the image as well as remove it if the download was cancelled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400252 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700253 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
254 for _, image := range cloned.ImageDownloads {
255 if image.Id == img.Id && image.Name == img.Name {
256 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
257 clonedImages = append(clonedImages, img)
258 }
259 }
260 }
261 cloned.ImageDownloads = clonedImages
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400262
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700263 // Set the Admin state to enabled if required
264 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
265 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400266 img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
267 cloned.AdminState = voltha.AdminState_ENABLED
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700268 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400269 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700270}
271
272func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530273 logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700274
Kent Hagermancba2f302020-07-28 13:37:36 -0400275 device, err := agent.getDeviceReadOnly(ctx)
276 if err != nil {
277 return nil, status.Errorf(codes.Aborted, "%s", err)
278 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400279 for _, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700280 if image.Id == img.Id && image.Name == img.Name {
281 return image, nil
282 }
283 }
284 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
285}
286
287func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
Himani Chawlab4c25912020-11-12 17:16:38 +0530288 logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700289
Kent Hagermancba2f302020-07-28 13:37:36 -0400290 device, err := agent.getDeviceReadOnly(ctx)
291 if err != nil {
292 return nil, status.Errorf(codes.Aborted, "%s", err)
293 }
294 return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700295}
Andrea Campanella025667e2021-01-14 11:50:07 +0100296
297// onImageFailure brings back the device to Enabled state and sets the image to image download_failed.
298func (agent *Agent) onImageFailure(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
299 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530300 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 +0100301 return
302 }
303 if res, ok := response.(error); ok {
304 logger.Errorw(ctx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
305 device := agent.cloneDeviceWithoutLock()
306 //TODO base this on IMAGE ID when created
307 var imageFailed *voltha.ImageDownload
308 var index int
309 if device.ImageDownloads != nil {
310 for pos, image := range device.ImageDownloads {
311 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
312 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
313 imageFailed = image
314 index = pos
315 }
316 }
317 }
318
319 if imageFailed == nil {
320 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
321 return
322 }
323
324 updatedImages := removeImage(device.ImageDownloads, index)
325
326 // Save the image
327 clonedImg := proto.Clone(imageFailed).(*voltha.ImageDownload)
328 if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
329 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
330 } else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
331 clonedImg.ImageState = voltha.ImageDownload_IMAGE_INACTIVE
332 }
333 cloned := agent.cloneDeviceWithoutLock()
334 cloned.ImageDownloads = append(updatedImages, clonedImg)
335 //Enabled is the only state we can go back to.
336 cloned.AdminState = voltha.AdminState_ENABLED
337 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
338 logger.Errorw(ctx, "failed-enable-device-after-image-failure",
339 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": res, "args": reqArgs})
340 }
341 } else {
342 logger.Errorw(ctx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
343 }
344 // TODO: Post failure message onto kafka
345}
346
347// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
348func (agent *Agent) onImageSuccess(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{}) {
349 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530350 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 +0100351 return
352 }
353 logger.Errorw(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
354 device := agent.cloneDeviceWithoutLock()
355 //TODO base this on IMAGE ID when created
356 var imageSucceeded *voltha.ImageDownload
357 var index int
358 if device.ImageDownloads != nil {
359 for pos, image := range device.ImageDownloads {
360 if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
361 image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
362 imageSucceeded = image
363 index = pos
364 }
365 }
366 }
367
368 if imageSucceeded == nil {
369 logger.Errorw(ctx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "args": reqArgs})
370 return
371 }
372
373 updatedImages := removeImage(device.ImageDownloads, index)
374
375 // Save the image
376 clonedImg := proto.Clone(imageSucceeded).(*voltha.ImageDownload)
377 if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
378 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
379 } else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
380 clonedImg.ImageState = voltha.ImageDownload_IMAGE_ACTIVE
381
382 }
383 cloned := agent.cloneDeviceWithoutLock()
384 cloned.ImageDownloads = append(updatedImages, clonedImg)
385
386 //Enabled is the only state we can go back to.
387 cloned.AdminState = voltha.AdminState_ENABLED
388 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
389 logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
390 log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response, "args": reqArgs})
391 }
392
393}
394
395func removeImage(s []*voltha.ImageDownload, i int) []*voltha.ImageDownload {
396 s[i] = s[len(s)-1]
397 // We do not need to put s[i] at the end, as it will be discarded anyway
398 return s[:len(s)-1]
399}