blob: 3bc91ca0741d587832687e0b50ef392095febacf [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"
21
22 "github.com/gogo/protobuf/proto"
23 "github.com/golang/protobuf/ptypes"
24 "github.com/opencord/voltha-lib-go/v3/pkg/log"
25 "github.com/opencord/voltha-protos/v3/go/voltha"
26 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/status"
28)
29
30func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
31 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
32 return nil, err
33 }
Rohan Agrawal31f21802020-06-12 05:38:46 +000034 logger.Debugw(ctx, "downloadImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070035
Kent Hagermanf6db9f12020-07-22 17:16:19 -040036 device := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070037 if device.AdminState != voltha.AdminState_ENABLED {
Kent Hagermanf6db9f12020-07-22 17:16:19 -040038 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070039 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
40 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040041 if device.AdminState != voltha.AdminState_ENABLED {
42 logger.Debugw(ctx, "device-not-enabled", log.Fields{"id": agent.deviceID})
43 agent.requestQueue.RequestComplete()
44 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
45 }
46
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070047 // Save the image
48 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
49 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
Kent Hagermanf6db9f12020-07-22 17:16:19 -040050 cloned := agent.cloneDeviceWithoutLock()
51 cloned.ImageDownloads = append(device.ImageDownloads, clonedImg)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070052
Kent Hagermanf6db9f12020-07-22 17:16:19 -040053 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
54 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
55 return nil, err
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070056 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -040057
58 // Send the request to the adapter
59 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
60 ch, err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg)
61 if err != nil {
62 cancel()
63 return nil, err
64 }
65 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
66
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070067 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
68}
69
70// isImageRegistered is a helper method to figure out if an image is already registered
71func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
72 for _, image := range device.ImageDownloads {
73 if image.Id == img.Id && image.Name == img.Name {
74 return true
75 }
76 }
77 return false
78}
79
80func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
81 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
82 return nil, err
83 }
Rohan Agrawal31f21802020-06-12 05:38:46 +000084 logger.Debugw(ctx, "cancelImageDownload", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070085
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070086 // Verify whether the Image is in the list of image being downloaded
Kent Hagermanf6db9f12020-07-22 17:16:19 -040087 device := agent.getDeviceReadOnly()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070088 if !isImageRegistered(img, device) {
Kent Hagermanf6db9f12020-07-22 17:16:19 -040089 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070090 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
91 }
92
93 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -040094 cloned := agent.cloneDeviceWithoutLock()
95 for _, image := range cloned.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070096 if image.Id == img.Id && image.Name == img.Name {
97 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
98 }
99 }
100
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400101 if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
102 agent.requestQueue.RequestComplete()
103 } else {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700104 // Set the device to Enabled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400105 cloned.AdminState = voltha.AdminState_ENABLED
106 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700107 return nil, err
108 }
109 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400110 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700111 if err != nil {
112 cancel()
113 return nil, err
114 }
115 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
116 }
117 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
118}
119
120func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
121 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
122 return nil, err
123 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000124 logger.Debugw(ctx, "activateImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700125
126 // Verify whether the Image is in the list of image being downloaded
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400127 device := agent.getDeviceReadOnly()
128 if !isImageRegistered(img, device) {
129 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700130 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
131 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400132 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
133 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700134 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
135 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400136
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700137 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400138 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700139 for _, image := range cloned.ImageDownloads {
140 if image.Id == img.Id && image.Name == img.Name {
141 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
142 }
143 }
144 // Set the device to downloading_image
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400145 cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
146 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700147 return nil, err
148 }
149
150 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400151 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700152 if err != nil {
153 cancel()
154 return nil, err
155 }
156 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
157
158 // The status of the AdminState will be changed following the update_download_status response from the adapter
159 // The image name will also be removed from the device list
160 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
161}
162
163func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
164 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
165 return nil, err
166 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000167 logger.Debugw(ctx, "revertImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700168
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700169 // Verify whether the Image is in the list of image being downloaded
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400170 device := agent.getDeviceReadOnly()
171 if !isImageRegistered(img, device) {
172 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700173 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
174 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400175 if device.AdminState != voltha.AdminState_ENABLED {
176 agent.requestQueue.RequestComplete()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700177 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
178 }
179 // Update image download state
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400180 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700181 for _, image := range cloned.ImageDownloads {
182 if image.Id == img.Id && image.Name == img.Name {
183 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
184 }
185 }
186
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400187 if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700188 return nil, err
189 }
190
191 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400192 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, cloned, img)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700193 if err != nil {
194 cancel()
195 return nil, err
196 }
197 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
198
199 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
200}
201
202func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000203 logger.Debugw(ctx, "getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700204
205 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
206 return nil, err
207 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400208 device := agent.getDeviceReadOnly()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700209 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
210 agent.requestQueue.RequestComplete()
211 if err != nil {
212 return nil, err
213 }
214 // Wait for the adapter response
215 rpcResponse, ok := <-ch
216 if !ok {
217 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
218 }
219 if rpcResponse.Err != nil {
220 return nil, rpcResponse.Err
221 }
222 // Successful response
223 imgDownload := &voltha.ImageDownload{}
224 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
225 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
226 }
227 return imgDownload, nil
228}
229
230func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
231 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
232 return err
233 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000234 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700235
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700236 // Update the image as well as remove it if the download was cancelled
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400237 cloned := agent.cloneDeviceWithoutLock()
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700238 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
239 for _, image := range cloned.ImageDownloads {
240 if image.Id == img.Id && image.Name == img.Name {
241 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
242 clonedImages = append(clonedImages, img)
243 }
244 }
245 }
246 cloned.ImageDownloads = clonedImages
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400247
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700248 // Set the Admin state to enabled if required
249 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
250 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400251 img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
252 cloned.AdminState = voltha.AdminState_ENABLED
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700253 }
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400254 return agent.updateDeviceAndReleaseLock(ctx, cloned)
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700255}
256
257func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
258 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
259 return nil, err
260 }
261 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000262 logger.Debugw(ctx, "getImageDownload", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700263
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400264 device := agent.getDeviceReadOnly()
265 for _, image := range device.ImageDownloads {
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700266 if image.Id == img.Id && image.Name == img.Name {
267 return image, nil
268 }
269 }
270 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
271}
272
273func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
274 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
275 return nil, err
276 }
277 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000278 logger.Debugw(ctx, "listImageDownloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700279
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400280 return &voltha.ImageDownloads{Items: agent.getDeviceReadOnly().ImageDownloads}, nil
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700281}