blob: 8d605313f859bd326134ddbb322c3251ec9d7a86 [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 }
34 defer agent.requestQueue.RequestComplete()
35
Rohan Agrawal31f21802020-06-12 05:38:46 +000036 logger.Debugw(ctx, "downloadImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070037
38 device := agent.getDeviceWithoutLock()
39
40 if device.AdminState != voltha.AdminState_ENABLED {
41 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
42 }
43 // Save the image
44 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
45 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
46 cloned := proto.Clone(device).(*voltha.Device)
47 if cloned.ImageDownloads == nil {
48 cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
49 } else {
50 if device.AdminState != voltha.AdminState_ENABLED {
Rohan Agrawal31f21802020-06-12 05:38:46 +000051 logger.Debugw(ctx, "device-not-enabled", log.Fields{"id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070052 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
53 }
54 // Save the image
55 clonedImg := proto.Clone(img).(*voltha.ImageDownload)
56 clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
57 if device.ImageDownloads == nil {
58 device.ImageDownloads = []*voltha.ImageDownload{clonedImg}
59 } else {
60 device.ImageDownloads = append(device.ImageDownloads, clonedImg)
61 }
62 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, device.ConnectStatus, device.OperStatus); err != nil {
63 return nil, err
64 }
65
66 // Send the request to the adapter
67 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
68 ch, err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg)
69 if err != nil {
70 cancel()
71 return nil, err
72 }
73 go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
74 }
75 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
76}
77
78// isImageRegistered is a helper method to figure out if an image is already registered
79func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
80 for _, image := range device.ImageDownloads {
81 if image.Id == img.Id && image.Name == img.Name {
82 return true
83 }
84 }
85 return false
86}
87
88func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
89 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
90 return nil, err
91 }
92 defer agent.requestQueue.RequestComplete()
93
Rohan Agrawal31f21802020-06-12 05:38:46 +000094 logger.Debugw(ctx, "cancelImageDownload", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -070095
96 device := agent.getDeviceWithoutLock()
97
98 // Verify whether the Image is in the list of image being downloaded
99 if !isImageRegistered(img, device) {
100 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
101 }
102
103 // Update image download state
104 for _, image := range device.ImageDownloads {
105 if image.Id == img.Id && image.Name == img.Name {
106 image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
107 }
108 }
109
110 if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
111 // Set the device to Enabled
112 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, device, voltha.AdminState_ENABLED, device.ConnectStatus, device.OperStatus); err != nil {
113 return nil, err
114 }
115 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
116 ch, err := agent.adapterProxy.CancelImageDownload(subCtx, device, img)
117 if err != nil {
118 cancel()
119 return nil, err
120 }
121 go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
122 }
123 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
124}
125
126func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
127 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
128 return nil, err
129 }
130 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000131 logger.Debugw(ctx, "activateImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700132 cloned := agent.getDeviceWithoutLock()
133
134 // Verify whether the Image is in the list of image being downloaded
135 if !isImageRegistered(img, cloned) {
136 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
137 }
138
139 if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
140 return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
141 }
142 // Update image download state
143 for _, image := range cloned.ImageDownloads {
144 if image.Id == img.Id && image.Name == img.Name {
145 image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
146 }
147 }
148 // Set the device to downloading_image
149 if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, cloned.ConnectStatus, cloned.OperStatus); err != nil {
150 return nil, err
151 }
152
153 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
154 ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
155 if err != nil {
156 cancel()
157 return nil, err
158 }
159 go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
160
161 // The status of the AdminState will be changed following the update_download_status response from the adapter
162 // The image name will also be removed from the device list
163 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
164}
165
166func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
167 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
168 return nil, err
169 }
170 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000171 logger.Debugw(ctx, "revertImage", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700172
173 cloned := agent.getDeviceWithoutLock()
174
175 // Verify whether the Image is in the list of image being downloaded
176 if !isImageRegistered(img, cloned) {
177 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
178 }
179
180 if cloned.AdminState != voltha.AdminState_ENABLED {
181 return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
182 }
183 // Update image download state
184 for _, image := range cloned.ImageDownloads {
185 if image.Id == img.Id && image.Name == img.Name {
186 image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
187 }
188 }
189
190 if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
191 return nil, err
192 }
193
194 subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
195 ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
196 if err != nil {
197 cancel()
198 return nil, err
199 }
200 go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
201
202 return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
203}
204
205func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000206 logger.Debugw(ctx, "getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700207
208 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
209 return nil, err
210 }
211 device := agent.getDeviceWithoutLock()
212 ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
213 agent.requestQueue.RequestComplete()
214 if err != nil {
215 return nil, err
216 }
217 // Wait for the adapter response
218 rpcResponse, ok := <-ch
219 if !ok {
220 return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
221 }
222 if rpcResponse.Err != nil {
223 return nil, rpcResponse.Err
224 }
225 // Successful response
226 imgDownload := &voltha.ImageDownload{}
227 if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
228 return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
229 }
230 return imgDownload, nil
231}
232
233func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
234 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
235 return err
236 }
237 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000238 logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700239
240 cloned := agent.getDeviceWithoutLock()
241
242 // Update the image as well as remove it if the download was cancelled
243 clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
244 for _, image := range cloned.ImageDownloads {
245 if image.Id == img.Id && image.Name == img.Name {
246 if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
247 clonedImages = append(clonedImages, img)
248 }
249 }
250 }
251 cloned.ImageDownloads = clonedImages
252 // Set the Admin state to enabled if required
253 if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
254 img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
255 (img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING) {
256 return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, cloned.OperStatus)
257 }
258 return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
259}
260
261func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
262 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
263 return nil, err
264 }
265 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000266 logger.Debugw(ctx, "getImageDownload", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700267
268 cloned := agent.getDeviceWithoutLock()
269 for _, image := range cloned.ImageDownloads {
270 if image.Id == img.Id && image.Name == img.Name {
271 return image, nil
272 }
273 }
274 return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
275}
276
277func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
278 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
279 return nil, err
280 }
281 defer agent.requestQueue.RequestComplete()
Rohan Agrawal31f21802020-06-12 05:38:46 +0000282 logger.Debugw(ctx, "listImageDownloads", log.Fields{"device-id": agent.deviceID})
Mahir Gunyelfa6ea272020-06-10 17:03:51 -0700283
284 return &voltha.ImageDownloads{Items: agent.getDeviceWithoutLock().ImageDownloads}, nil
285}