[VOL-3740] Adding intial Command for Image download and Activate

Change-Id: I9c84e4fbb0d25338a7099e32ab85cc79f896f908
diff --git a/VERSION b/VERSION
index 3a3cd8c..c3f0d2b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.1
+1.4.0-dev
diff --git a/internal/pkg/commands/devices.go b/internal/pkg/commands/devices.go
index d41b9ac..416e1c5 100644
--- a/internal/pkg/commands/devices.go
+++ b/internal/pkg/commands/devices.go
@@ -45,6 +45,7 @@
 	DEFAULT_DEVICE_PM_CONFIG_METRIC_LIST_FORMAT = "table{{.Name}}\t{{.Type}}\t{{.Enabled}}\t{{.SampleFreq}}"
 	DEFAULT_DEVICE_PM_CONFIG_GROUP_LIST_FORMAT  = "table{{.GroupName}}\t{{.Enabled}}\t{{.GroupFreq}}"
 	DEFAULT_DEVICE_VALUE_GET_FORMAT             = "table{{.Name}}\t{{.Result}}"
+	DEFAULT_DEVICE_IMAGE_LIST_GET_FORMAT        = "table{{.Name}}\t{{.Url}}\t{{.Crc}}\t{{.DownloadState}}\t{{.ImageVersion}}\t{{.LocalDir}}\t{{.ImageState}}\t{{.FileSize}}"
 )
 
 type DeviceList struct {
@@ -206,6 +207,34 @@
 	} `positional-args:"yes"`
 }
 
+type DeviceOnuListImages struct {
+	ListOutputOptions
+	Args struct {
+		Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+	} `positional-args:"yes"`
+}
+
+type DeviceOnuDownloadImage struct {
+	Args struct {
+		Id           DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+		Name         string   `positional-arg-name:"IMAGE_NAME" required:"yes"`
+		Url          string   `positional-arg-name:"IMAGE_URL" required:"yes"`
+		ImageVersion string   `positional-arg-name:"IMAGE_VERSION" required:"yes"`
+		Crc          uint32   `positional-arg-name:"IMAGE_CRC" required:"yes"`
+		LocalDir     string   `positional-arg-name:"IMAGE_LOCAL_DIRECTORY"`
+	} `positional-args:"yes"`
+}
+
+type DeviceOnuActivateImageUpdate struct {
+	Args struct {
+		Id           DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+		Name         string   `positional-arg-name:"IMAGE_NAME" required:"yes"`
+		ImageVersion string   `positional-arg-name:"IMAGE_VERSION" required:"yes"`
+		SaveConfig   bool     `positional-arg-name:"SAVE_EXISTING_CONFIG"`
+		LocalDir     string   `positional-arg-name:"IMAGE_LOCAL_DIRECTORY"`
+	} `positional-args:"yes"`
+}
+
 type DeviceOpts struct {
 	List    DeviceList     `command:"list"`
 	Create  DeviceCreate   `command:"create"`
@@ -245,6 +274,12 @@
 			List DevicePmConfigGroupMetricList `command:"list"`
 		} `command:"groupmetric"`
 	} `command:"pmconfig"`
+
+	Image struct {
+		Get      DeviceOnuListImages          `command:"list"`
+		Download DeviceOnuDownloadImage       `command:"download"`
+		Activate DeviceOnuActivateImageUpdate `command:"activate"`
+	} `command:"image"`
 }
 
 var deviceOpts = DeviceOpts{}
@@ -1268,6 +1303,114 @@
 
 }
 
+func (options *DeviceOnuListImages) Execute(args []string) error {
+
+	conn, err := NewConnection()
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+
+	client := voltha.NewVolthaServiceClient(conn)
+
+	ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	id := common.ID{Id: string(options.Args.Id)}
+
+	imageDownloads, err := client.ListImageDownloads(ctx, &id)
+	if err != nil {
+		return err
+	}
+
+	outputFormat := CharReplacer.Replace(options.Format)
+	if outputFormat == "" {
+		outputFormat = GetCommandOptionWithDefault("device-image-list", "format", DEFAULT_DEVICE_IMAGE_LIST_GET_FORMAT)
+	}
+
+	if options.Quiet {
+		outputFormat = "{{.Id}}"
+	}
+
+	//TODO orderby
+
+	// Make sure json output prints an empty list, not "null"
+	if imageDownloads.Items == nil {
+		imageDownloads.Items = make([]*voltha.ImageDownload, 0)
+	}
+
+	result := CommandResult{
+		Format:    format.Format(outputFormat),
+		OutputAs:  toOutputType(options.OutputAs),
+		NameLimit: options.NameLimit,
+		Data:      imageDownloads.Items,
+	}
+
+	GenerateOutput(&result)
+	return nil
+
+}
+
+func (options *DeviceOnuDownloadImage) Execute(args []string) error {
+
+	conn, err := NewConnection()
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+
+	client := voltha.NewVolthaServiceClient(conn)
+
+	ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	downloadImage := voltha.ImageDownload{
+		Id:       string(options.Args.Id),
+		Name:     options.Args.Name,
+		Url:      options.Args.Url,
+		Crc:      options.Args.Crc,
+		LocalDir: options.Args.LocalDir,
+	}
+
+	_, err = client.DownloadImage(ctx, &downloadImage)
+	if err != nil {
+		return err
+	}
+
+	return nil
+
+}
+
+func (options *DeviceOnuActivateImageUpdate) Execute(args []string) error {
+
+	conn, err := NewConnection()
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+
+	client := voltha.NewVolthaServiceClient(conn)
+
+	ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+	defer cancel()
+
+	downloadImage := voltha.ImageDownload{
+		Id:           string(options.Args.Id),
+		Name:         options.Args.Name,
+		ImageVersion: options.Args.ImageVersion,
+		SaveConfig:   options.Args.SaveConfig,
+		LocalDir:     options.Args.LocalDir,
+	}
+
+	_, err = client.ActivateImageUpdate(ctx, &downloadImage)
+	if err != nil {
+		return err
+	}
+
+	return nil
+
+}
+
 type ReturnValueRow struct {
 	Name   string      `json:"name"`
 	Result interface{} `json:"result"`