[VOL-3215] Reorganize functions in agent.go
Functions moved without any change in contents

Change-Id: I42ba327e648bacf25e5d328743835b36be89f4b4
diff --git a/rw_core/core/device/agent_image.go b/rw_core/core/device/agent_image.go
new file mode 100644
index 0000000..208d817
--- /dev/null
+++ b/rw_core/core/device/agent_image.go
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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"
+
+	"github.com/gogo/protobuf/proto"
+	"github.com/golang/protobuf/ptypes"
+	"github.com/opencord/voltha-lib-go/v3/pkg/log"
+	"github.com/opencord/voltha-protos/v3/go/voltha"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+func (agent *Agent) downloadImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+
+	logger.Debugw("downloadImage", log.Fields{"device-id": agent.deviceID})
+
+	device := agent.getDeviceWithoutLock()
+
+	if device.AdminState != voltha.AdminState_ENABLED {
+		return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
+	}
+	// Save the image
+	clonedImg := proto.Clone(img).(*voltha.ImageDownload)
+	clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
+	cloned := proto.Clone(device).(*voltha.Device)
+	if cloned.ImageDownloads == nil {
+		cloned.ImageDownloads = []*voltha.ImageDownload{clonedImg}
+	} else {
+		if device.AdminState != voltha.AdminState_ENABLED {
+			logger.Debugw("device-not-enabled", log.Fields{"id": agent.deviceID})
+			return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, expected-admin-state:%s", agent.deviceID, voltha.AdminState_ENABLED)
+		}
+		// Save the image
+		clonedImg := proto.Clone(img).(*voltha.ImageDownload)
+		clonedImg.DownloadState = voltha.ImageDownload_DOWNLOAD_REQUESTED
+		if device.ImageDownloads == nil {
+			device.ImageDownloads = []*voltha.ImageDownload{clonedImg}
+		} else {
+			device.ImageDownloads = append(device.ImageDownloads, clonedImg)
+		}
+		if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, device.ConnectStatus, device.OperStatus); err != nil {
+			return nil, err
+		}
+
+		// Send the request to the adapter
+		subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
+		ch, err := agent.adapterProxy.DownloadImage(ctx, cloned, clonedImg)
+		if err != nil {
+			cancel()
+			return nil, err
+		}
+		go agent.waitForAdapterResponse(subCtx, cancel, "downloadImage", ch, agent.onSuccess, agent.onFailure)
+	}
+	return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
+}
+
+// isImageRegistered is a helper method to figure out if an image is already registered
+func isImageRegistered(img *voltha.ImageDownload, device *voltha.Device) bool {
+	for _, image := range device.ImageDownloads {
+		if image.Id == img.Id && image.Name == img.Name {
+			return true
+		}
+	}
+	return false
+}
+
+func (agent *Agent) cancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+
+	logger.Debugw("cancelImageDownload", log.Fields{"device-id": agent.deviceID})
+
+	device := agent.getDeviceWithoutLock()
+
+	// Verify whether the Image is in the list of image being downloaded
+	if !isImageRegistered(img, device) {
+		return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
+	}
+
+	// Update image download state
+	for _, image := range device.ImageDownloads {
+		if image.Id == img.Id && image.Name == img.Name {
+			image.DownloadState = voltha.ImageDownload_DOWNLOAD_CANCELLED
+		}
+	}
+
+	if device.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
+		// Set the device to Enabled
+		if err := agent.updateDeviceStateInStoreWithoutLock(ctx, device, voltha.AdminState_ENABLED, device.ConnectStatus, device.OperStatus); err != nil {
+			return nil, err
+		}
+		subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
+		ch, err := agent.adapterProxy.CancelImageDownload(subCtx, device, img)
+		if err != nil {
+			cancel()
+			return nil, err
+		}
+		go agent.waitForAdapterResponse(subCtx, cancel, "cancelImageDownload", ch, agent.onSuccess, agent.onFailure)
+	}
+	return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
+}
+
+func (agent *Agent) activateImage(ctx context.Context, img *voltha.ImageDownload) (*voltha.OperationResp, error) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+	logger.Debugw("activateImage", log.Fields{"device-id": agent.deviceID})
+	cloned := agent.getDeviceWithoutLock()
+
+	// Verify whether the Image is in the list of image being downloaded
+	if !isImageRegistered(img, cloned) {
+		return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, image-not-registered:%s", agent.deviceID, img.Name)
+	}
+
+	if cloned.AdminState == voltha.AdminState_DOWNLOADING_IMAGE {
+		return nil, status.Errorf(codes.FailedPrecondition, "device-id:%s, device-in-downloading-state:%s", agent.deviceID, img.Name)
+	}
+	// Update image download state
+	for _, image := range cloned.ImageDownloads {
+		if image.Id == img.Id && image.Name == img.Name {
+			image.ImageState = voltha.ImageDownload_IMAGE_ACTIVATING
+		}
+	}
+	// Set the device to downloading_image
+	if err := agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_DOWNLOADING_IMAGE, cloned.ConnectStatus, cloned.OperStatus); err != nil {
+		return nil, err
+	}
+
+	subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
+	ch, err := agent.adapterProxy.ActivateImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
+	if err != nil {
+		cancel()
+		return nil, err
+	}
+	go agent.waitForAdapterResponse(subCtx, cancel, "activateImageUpdate", ch, agent.onSuccess, agent.onFailure)
+
+	// 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) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+	logger.Debugw("revertImage", log.Fields{"device-id": agent.deviceID})
+
+	cloned := agent.getDeviceWithoutLock()
+
+	// Verify whether the Image is in the list of image being downloaded
+	if !isImageRegistered(img, cloned) {
+		return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, image-not-registered:%s", agent.deviceID, img.Name)
+	}
+
+	if cloned.AdminState != voltha.AdminState_ENABLED {
+		return nil, status.Errorf(codes.FailedPrecondition, "deviceId:%s, device-not-enabled-state:%s", agent.deviceID, img.Name)
+	}
+	// Update image download state
+	for _, image := range cloned.ImageDownloads {
+		if image.Id == img.Id && image.Name == img.Name {
+			image.ImageState = voltha.ImageDownload_IMAGE_REVERTING
+		}
+	}
+
+	if err := agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, ""); err != nil {
+		return nil, err
+	}
+
+	subCtx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
+	ch, err := agent.adapterProxy.RevertImageUpdate(subCtx, proto.Clone(cloned).(*voltha.Device), img)
+	if err != nil {
+		cancel()
+		return nil, err
+	}
+	go agent.waitForAdapterResponse(subCtx, cancel, "revertImageUpdate", ch, agent.onSuccess, agent.onFailure)
+
+	return &voltha.OperationResp{Code: voltha.OperationResp_OPERATION_SUCCESS}, nil
+}
+
+func (agent *Agent) getImageDownloadStatus(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
+	logger.Debugw("getImageDownloadStatus", log.Fields{"device-id": agent.deviceID})
+
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	device := agent.getDeviceWithoutLock()
+	ch, err := agent.adapterProxy.GetImageDownloadStatus(ctx, device, img)
+	agent.requestQueue.RequestComplete()
+	if err != nil {
+		return nil, err
+	}
+	// Wait for the adapter response
+	rpcResponse, ok := <-ch
+	if !ok {
+		return nil, status.Errorf(codes.Aborted, "channel-closed-device-id-%s", agent.deviceID)
+	}
+	if rpcResponse.Err != nil {
+		return nil, rpcResponse.Err
+	}
+	// Successful response
+	imgDownload := &voltha.ImageDownload{}
+	if err := ptypes.UnmarshalAny(rpcResponse.Reply, imgDownload); err != nil {
+		return nil, status.Errorf(codes.InvalidArgument, "%s", err.Error())
+	}
+	return imgDownload, nil
+}
+
+func (agent *Agent) updateImageDownload(ctx context.Context, img *voltha.ImageDownload) error {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return err
+	}
+	defer agent.requestQueue.RequestComplete()
+	logger.Debugw("updating-image-download", log.Fields{"device-id": agent.deviceID, "img": img})
+
+	cloned := agent.getDeviceWithoutLock()
+
+	// 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) {
+		return agent.updateDeviceStateInStoreWithoutLock(ctx, cloned, voltha.AdminState_ENABLED, cloned.ConnectStatus, cloned.OperStatus)
+	}
+	return agent.updateDeviceInStoreWithoutLock(ctx, cloned, false, "")
+}
+
+func (agent *Agent) getImageDownload(ctx context.Context, img *voltha.ImageDownload) (*voltha.ImageDownload, error) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+	logger.Debugw("getImageDownload", log.Fields{"device-id": agent.deviceID})
+
+	cloned := agent.getDeviceWithoutLock()
+	for _, image := range cloned.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) {
+	if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
+		return nil, err
+	}
+	defer agent.requestQueue.RequestComplete()
+	logger.Debugw("listImageDownloads", log.Fields{"device-id": agent.deviceID})
+
+	return &voltha.ImageDownloads{Items: agent.getDeviceWithoutLock().ImageDownloads}, nil
+}