blob: b27f47e542208f4429d2360e45debc675eb17401 [file] [log] [blame]
/*
* Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package device
import (
"context"
"errors"
"time"
ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
"github.com/opencord/voltha-protos/v5/go/common"
"github.com/gogo/protobuf/proto"
coreutils "github.com/opencord/voltha-go/rw_core/utils"
"github.com/opencord/voltha-lib-go/v7/pkg/log"
"github.com/opencord/voltha-protos/v5/go/voltha"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
var err error
var desc string
var prevAdminState, currAdminState common.AdminState_Types
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, operStatus, err, desc) }()
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "download-image", log.Fields{"device-id": agent.deviceID})
if agent.device.Root {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
"not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
return nil, err
}
device := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(device) {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
return nil, err
}
if device.ImageDownloads != nil {
for _, image := range device.ImageDownloads {
if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
err = status.Errorf(codes.FailedPrecondition, "device-id:%s, already downloading image:%s",
agent.deviceID, image.Name)
agent.requestQueue.RequestComplete()
return nil, err
}
}
}
// Save the image
clonedImg := proto.Clone(img).(*voltha.ImageDownload)
clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
cloned := agent.cloneDeviceWithoutLock()
_, index, err := getImage(img, device)
if err != nil {
cloned.ImageDownloads = append(cloned.ImageDownloads, clonedImg)
} else {
cloned.ImageDownloads[index] = clonedImg
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": device.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
go func() {
defer cancel()
response, err := client.DownloadImage(subCtx, &ca.ImageDownloadMessage{
Device: cloned,
Image: clonedImg,
})
if err == nil {
agent.onImageSuccess(subCtx, response)
} else {
agent.onImageFailure(subCtx, err)
}
}()
cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
return nil, err
}
return &common.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
}
// getImage is a helper method to figure out if an image is already registered
func getImage(img *voltha.ImageDownload, device *voltha.Device) (*voltha.ImageDownload, int, error) {
for pos, image := range device.ImageDownloads {
if image.Id == img.Id && image.Name == img.Name {
return image, pos, nil
}
}
return nil, -1, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s",
device.Id, img.Name)
}
func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
var err error
var desc string
var prevAdminState, currAdminState common.AdminState_Types
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, &prevAdminState, &currAdminState, operStatus, err, desc) }()
if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "cancel-image-download", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
return nil, err
}
// Update image download state
_, index, err := getImage(img, cloned)
if err != nil {
agent.requestQueue.RequestComplete()
return nil, err
}
prevAdminState = cloned.AdminState
cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
if cloned.AdminState != voltha.AdminState_DOWNLOADING_IMAGE {
err = status.Errorf(codes.Aborted, "device not in image download state %s", cloned.Id)
agent.requestQueue.RequestComplete()
return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_FAILURE}, err
}
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
go func() {
defer cancel()
response, err := client.CancelImageDownload(subCtx, &ca.ImageDownloadMessage{
Device: cloned,
Image: img,
})
if err == nil {
agent.onImageSuccess(subCtx, response)
} else {
agent.onImageFailure(subCtx, err)
}
}()
// Set the device to Enabled
cloned.AdminState = voltha.AdminState_ENABLED
if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
return nil, err
}
currAdminState = cloned.AdminState
return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
}
func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
var err error
var desc string
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "activate-image", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
agent.requestQueue.RequestComplete()
return nil, err
}
// Update image download state
image, index, err := getImage(img, cloned)
if err != nil {
agent.requestQueue.RequestComplete()
return nil, err
}
if image.DownloadState != voltha.ImageDownload_DOWNLOAD_SUCCEEDED {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "device-id:%s, device-has-not-downloaded-image:%s", agent.deviceID, img.Name)
return nil, err
}
//TODO does this need to be removed ?
if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
return nil, err
}
// Update the image
cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
cloned.AdminState = voltha.AdminState_DOWNLOADING_IMAGE
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
go func() {
defer cancel()
response, err := client.ActivateImageUpdate(subCtx, &ca.ImageDownloadMessage{
Device: cloned,
Image: img,
})
if err == nil {
agent.onImageSuccess(subCtx, response)
} else {
agent.onImageFailure(subCtx, err)
}
}()
// Save the image
if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
return nil, err
}
// The status of the AdminState will be changed following the update_download_status response from the adapter
// The image name will also be removed from the device list
return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
}
func (agent *Agent) revertImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
var err error
var desc string
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "revert-image", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
return nil, err
}
// Update image download state
_, index, err := getImage(img, cloned)
if err != nil {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
return nil, err
}
if cloned.AdminState != voltha.AdminState_ENABLED {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
return nil, err
}
cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_REVERTING
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
operStatus.Code = common.OperationResp_OPERATION_IN_PROGRESS
go func() {
defer cancel()
_, err := client.RevertImageUpdate(subCtx, &ca.ImageDownloadMessage{
Device: cloned,
Image: img,
})
if err == nil {
agent.onSuccess(subCtx, nil, nil, true)
} else {
agent.onFailure(subCtx, err, nil, nil, true)
}
}()
// Save data
if err := agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
return nil, err
}
return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
}
func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
logger.Debugw(ctx, "get-image-download-status", log.Fields{"device-id": agent.deviceID})
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
device := agent.getDeviceReadOnlyWithoutLock()
if !agent.proceedWithRequest(device) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": device.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
agent.requestQueue.RequestComplete()
return client.GetImageDownloadStatus(ctx, &ca.ImageDownloadMessage{
Device: device,
Image: img,
})
}
func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
var err error
var desc string
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return err
}
logger.Debugw(ctx, "updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
return err
}
// Update the image as well as remove it if the download was cancelled
clonedImages := make([]*voltha.ImageDownload, len(cloned.ImageDownloads))
for _, image := range cloned.ImageDownloads {
if image.Id == img.Id && image.Name == img.Name {
if image.DownloadState != voltha.ImageDownload_DOWNLOAD_CANCELLED {
clonedImages = append(clonedImages, img)
}
}
}
cloned.ImageDownloads = clonedImages
// Set the Admin state to enabled if required
if (img.DownloadState != voltha.ImageDownload_DOWNLOAD_REQUESTED &&
img.DownloadState != voltha.ImageDownload_DOWNLOAD_STARTED) ||
img.ImageState != voltha.ImageDownload_IMAGE_ACTIVATING {
cloned.AdminState = voltha.AdminState_ENABLED
}
return agent.updateDeviceAndReleaseLock(ctx, cloned)
}
func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
logger.Debugw(ctx, "get-image-download", log.Fields{"device-id": agent.deviceID})
device, err := agent.getDeviceReadOnly(ctx)
if err != nil {
return nil, status.Errorf(codes.Aborted, "%s", err)
}
for _, image := range device.ImageDownloads {
if image.Id == img.Id && image.Name == img.Name {
return image, nil
}
}
return nil, status.Errorf(codes.NotFound, "image-not-found:%s", img.Name)
}
func (agent *Agent) listImageDownloads(ctx context.Context, deviceID string) (*voltha.ImageDownloads, error) {
logger.Debugw(ctx, "list-image-downloads", log.Fields{"device-id": agent.deviceID})
device, err := agent.getDeviceReadOnly(ctx)
if err != nil {
return nil, status.Errorf(codes.Aborted, "%s", err)
}
return &voltha.ImageDownloads{Items: device.ImageDownloads}, nil
}
// onImageFailure brings back the device to Enabled state and sets the image to image download_failed.
func (agent *Agent) onImageFailure(ctx context.Context, imgErr error) {
// original context has failed due to timeout , let's open a new one
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
defer cancel()
rpc := coreutils.GetRPCMetadataFromContext(subCtx)
defer func() {
eCtx := coreutils.WithSpanAndRPCMetadataFromContext(ctx)
rpce := agent.deviceMgr.NewRPCEvent(eCtx, agent.deviceID, imgErr.Error(), nil)
go agent.deviceMgr.SendRPCEvent(eCtx, "RPC_ERROR_RAISE_EVENT", rpce,
voltha.EventCategory_COMMUNICATION, nil, time.Now().Unix())
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
desc := "adapter-response"
agent.logDeviceUpdate(ctx, nil, nil, operStatus, imgErr, desc)
}()
if err := agent.requestQueue.WaitForGreenLight(subCtx); err != nil {
logger.Errorw(subCtx, "can't obtain lock", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": err})
return
}
device := agent.getDeviceReadOnlyWithoutLock()
if !agent.proceedWithRequest(device) {
agent.requestQueue.RequestComplete()
logger.Errorw(subCtx, "Cannot complete operation as device deletion is in progress or reconciling is in progress/failed.",
log.Fields{"rpc": rpc, "device-id": agent.deviceID})
return
}
if imgErr != nil {
logger.Errorw(subCtx, "rpc-failed", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": imgErr})
cloned := agent.cloneDeviceWithoutLock()
//TODO base this on IMAGE ID when created
var imageFailed *voltha.ImageDownload
var index int
if cloned.ImageDownloads != nil {
for pos, image := range cloned.ImageDownloads {
if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
imageFailed = image
index = pos
}
}
}
if imageFailed == nil {
logger.Errorw(subCtx, "can't find image", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
return
}
//update image state on failure
if imageFailed.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_FAILED
} else if imageFailed.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_INACTIVE
}
//Enabled is the only state we can go back to.
cloned.AdminState = voltha.AdminState_ENABLED
if err := agent.updateDeviceAndReleaseLock(subCtx, cloned); err != nil {
logger.Errorw(subCtx, "failed-enable-device-after-image-failure",
log.Fields{"rpc": rpc, "device-id": agent.deviceID, "error": err})
}
} else {
logger.Errorw(subCtx, "rpc-failed-invalid-error", log.Fields{"rpc": rpc, "device-id": agent.deviceID})
return
}
}
// onImageSuccess brings back the device to Enabled state and sets the image to image download_failed.
func (agent *Agent) onImageSuccess(ctx context.Context, response interface{}) {
rpc := coreutils.GetRPCMetadataFromContext(ctx)
var err error
var desc string
operStatus := &common.OperationResp{Code: common.OperationResp_OPERATION_FAILURE}
defer func() { agent.logDeviceUpdate(ctx, nil, nil, operStatus, err, desc) }()
if err = agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return
}
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
err = status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
return
}
logger.Infow(ctx, "rpc-successful", log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response})
//TODO base this on IMAGE ID when created
var imageSucceeded *voltha.ImageDownload
var index int
if cloned.ImageDownloads != nil {
for pos, image := range cloned.ImageDownloads {
if image.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED ||
image.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
imageSucceeded = image
index = pos
}
}
}
if imageSucceeded == nil {
err = errors.New("can't find image")
return
}
//update image state on success
if imageSucceeded.DownloadState == voltha.ImageDownload_DOWNLOAD_REQUESTED {
cloned.ImageDownloads[index].DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
} else if imageSucceeded.ImageState == voltha.ImageDownload_IMAGE_ACTIVATING {
cloned.ImageDownloads[index].ImageState = voltha.ImageDownload_IMAGE_ACTIVE
}
//Enabled is the only state we can go back to.
cloned.AdminState = voltha.AdminState_ENABLED
if err = agent.updateDeviceAndReleaseLock(ctx, cloned); err != nil {
logger.Errorw(ctx, "failed-enable-device-after-image-download-success",
log.Fields{"rpc": rpc, "device-id": agent.deviceID, "response": response})
}
// Update operation status
if err == nil {
operStatus.Code = common.OperationResp_OPERATION_SUCCESS
}
}
func (agent *Agent) downloadImageToDevice(ctx context.Context, request *voltha.DeviceImageDownloadRequest) (*voltha.DeviceImageResponse, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "download-image-to-device", log.Fields{"device-id": agent.deviceID})
if agent.device.Root {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, is an OLT. Image update "+
"not supported by VOLTHA. Use Device Manager or other means", agent.deviceID)
}
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
defer cancel()
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
agent.requestQueue.RequestComplete()
return client.DownloadOnuImage(subCtx, request)
}
func (agent *Agent) getImageStatus(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "get-image-status", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
defer cancel()
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
agent.requestQueue.RequestComplete()
return client.GetOnuImageStatus(subCtx, request)
}
func (agent *Agent) activateImageOnDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "activate-image-on-device", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
defer cancel()
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
agent.requestQueue.RequestComplete()
return client.ActivateOnuImage(subCtx, request)
}
func (agent *Agent) abortImageUpgradeToDevice(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "abort-image-on-device", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
defer cancel()
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
agent.requestQueue.RequestComplete()
return client.AbortOnuImageUpgrade(subCtx, request)
}
func (agent *Agent) commitImage(ctx context.Context, request *voltha.DeviceImageRequest) (*voltha.DeviceImageResponse, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debugw(ctx, "commit-image-on-device", log.Fields{"device-id": agent.deviceID})
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.rpcTimeout)
defer cancel()
subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
agent.requestQueue.RequestComplete()
return client.CommitOnuImage(subCtx, request)
}
func (agent *Agent) getOnuImages(ctx context.Context, id *common.ID) (*voltha.OnuImages, error) {
if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
return nil, err
}
logger.Debug(ctx, "get-onu-images")
cloned := agent.cloneDeviceWithoutLock()
if !agent.proceedWithRequest(cloned) {
agent.requestQueue.RequestComplete()
return nil, status.Errorf(codes.FailedPrecondition, "%s", "cannot complete operation as device deletion is in progress or reconciling is in progress/failed")
}
// Send the request to the adapter
client, err := agent.adapterMgr.GetAdapterClient(ctx, agent.adapterEndpoint)
if err != nil {
logger.Errorw(ctx, "grpc-client-nil",
log.Fields{
"error": err,
"device-id": agent.deviceID,
"device-type": agent.deviceType,
"adapter-endpoint": cloned.AdapterEndpoint,
})
agent.requestQueue.RequestComplete()
return nil, err
}
agent.requestQueue.RequestComplete()
return client.GetOnuImages(ctx, id)
}