Skip to content

Commit

Permalink
Added image import cmd (kubernetes-sigs#1216)
Browse files Browse the repository at this point in the history
  • Loading branch information
KeerthanaAP authored May 12, 2023
1 parent c8f7c1a commit 0bbe9ec
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 2 deletions.
Binary file added cmd/capibmadm/capibmadm
Binary file not shown.
1 change: 1 addition & 0 deletions cmd/capibmadm/cmd/powervs/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func Commands() *cobra.Command {
options.AddCommonFlags(cmd)

cmd.AddCommand(ListCommand())
cmd.AddCommand(ImportCommand())

return cmd
}
188 changes: 188 additions & 0 deletions cmd/capibmadm/cmd/powervs/image/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
Copyright 2023 The Kubernetes Authors.
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 image

import (
"context"
"fmt"
"strings"
"time"

"github.com/spf13/cobra"

powerClient "github.com/IBM-Cloud/power-go-client/clients/instance"
"github.com/IBM-Cloud/power-go-client/power/models"

"k8s.io/apimachinery/pkg/util/wait"

logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"

"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/clients/powervs"
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/options"
"sigs.k8s.io/cluster-api-provider-ibmcloud/cmd/capibmadm/utils"
)

type imageImportOptions struct {
BucketName string
Region string
ImageFilename string
ImageName string
AccessKey string
SecretKey string
StorageType string
InstanceID string
Public bool
WatchTimeout time.Duration
}

// ImportCommand import image PowerVS instances.
func ImportCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "import",
Short: "Import the image into PowerVS instances",
Example: `
# Import image in PowerVS instances.
export IBMCLOUD_API_KEY=<api-key>
# import image using default storage type (service credential will be autogenerated)
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --object rhel-83-10032020.ova.gz --name test-image -r <region> --zone <zone>
# import image using default storage type with specifying the accesskey and secretkey explicitly
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --accesskey <accesskey> --secretkey <secretkey> --object rhel-83-10032020.ova.gz --name test-image -r <region> --zone <zone>
# with user provided storage type
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --pvs-storagetype <storagetype> --object rhel-83-10032020.ova.gz --name test-image -r <region> --zone <zone>
# import image from a public IBM Cloud Storage bucket
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --zone <zone> -r <region> --object rhel-83-10032020.ova.gz --name test_image --public-bucket
`,
}
var imageImportOption imageImportOptions
cmd.Flags().StringVarP(&imageImportOption.BucketName, "bucket", "b", "", "Cloud Object Storage bucket name.")
cmd.Flags().StringVarP(&imageImportOption.Region, "bucket-region", "r", "", "Cloud Object Storage bucket location.")
cmd.Flags().StringVar(&imageImportOption.ImageFilename, "object", "", "Cloud Object Storage object name.")
cmd.Flags().StringVar(&imageImportOption.AccessKey, "accesskey", "", "Cloud Object Storage HMAC access key.")
cmd.Flags().StringVar(&imageImportOption.SecretKey, "secretkey", "", "Cloud Object Storage HMAC secret key.")
cmd.Flags().StringVar(&imageImportOption.ImageName, "name", "", "Name to PowerVS imported image.")
cmd.Flags().BoolVarP(&imageImportOption.Public, "public-bucket", "", false, "Cloud Object Storage public bucket.")
cmd.Flags().DurationVar(&imageImportOption.WatchTimeout, "watch-timeout", 1*time.Hour, "watch timeout")
cmd.Flags().StringVar(&imageImportOption.StorageType, "pvs-storagetype", "tier3", "PowerVS Storage type, accepted values are [tier1, tier3].")
_ = cmd.MarkFlagRequired("bucket")
_ = cmd.MarkFlagRequired("bucket-region")
_ = cmd.MarkFlagRequired("name")
_ = cmd.MarkFlagRequired("object")
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
case1 := imageImportOption.AccessKey == "" && imageImportOption.SecretKey != ""
case2 := imageImportOption.AccessKey != "" && imageImportOption.SecretKey == ""

if case1 || case2 {
return fmt.Errorf("required both --accesskey and --secretkey values")
}
return nil
}

cmd.RunE = func(cmd *cobra.Command, args []string) error {
return importimage(cmd.Context(), imageImportOption)
}

options.AddCommonFlags(cmd)
return cmd
}

func importimage(ctx context.Context, imageImportOption imageImportOptions) error {
log := logf.Log
log.Info("Importing PowerVS images: ", "service-instance-id", options.GlobalOptions.ServiceInstanceID)

accountID, err := utils.GetAccountID(ctx)
if err != nil {
return err
}

sess, err := powervs.NewPISession(accountID, options.GlobalOptions.PowerVSZone, options.GlobalOptions.Debug)
if err != nil {
return err
}
// By default Bucket Access is private
bucketAccess := "private"

if imageImportOption.Public {
bucketAccess = "public"
}

body := &models.CreateCosImageImportJob{
BucketAccess: &bucketAccess,
BucketName: &imageImportOption.BucketName,
ImageFilename: &imageImportOption.ImageFilename,
ImageName: &imageImportOption.ImageName,
AccessKey: imageImportOption.AccessKey,
SecretKey: imageImportOption.SecretKey,
Region: &imageImportOption.Region,
StorageType: strings.ToLower(imageImportOption.StorageType),
}
imageClient := powerClient.NewIBMPIImageClient(ctx, sess, options.GlobalOptions.ServiceInstanceID)
jobRef, err := imageClient.CreateCosImage(body)
if err != nil {
return err
}

start := time.Now()
pollErr := wait.PollImmediate(2*time.Minute, imageImportOption.WatchTimeout, func() (bool, error) {
jobclient := powerClient.NewIBMPIJobClient(ctx, sess, options.GlobalOptions.ServiceInstanceID)
job, err := jobclient.Get(*jobRef.ID)
if err != nil {
return false, err
}

if *job.Status.State == "completed" {
return true, nil
}
if *job.Status.State == "failed" {
return false, fmt.Errorf("image import job failed to complete, err: %v", job.Status.Message)
}
log.Info("Image Import Job in-progress,", "current state", job.Status.State)
return false, nil
})
if pollErr == wait.ErrWaitTimeout {
pollErr = fmt.Errorf("timed out while waiting for image import job to complete")
}

if pollErr != nil {
return fmt.Errorf("image import job failed to complete, err: %v", pollErr)
}

log.Info("Retrieving image details")
images, err := imageClient.GetAll()
if err != nil {
return err
}
var image *models.ImageReference
for _, img := range images.Images {
if *img.Name == imageImportOption.ImageName {
image = img
break
}
}

if image == nil {
err := fmt.Errorf("unable to retrieve image details")
return err
}

msg := fmt.Sprintf("Successfully imported the image: %s with ID: %s within %s", *image.Name, *image.ImageID, time.Since(start))
log.Info(msg)

return nil
}
50 changes: 49 additions & 1 deletion docs/book/src/topics/capibmadm/powervs/image.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
## PowerVS Image Commands

### 1. capibmadm powervs image list
### 1. capibmadm powervs image import

#### Usage:
Import PowerVS image.

#### Environmental Variable:
IBMCLOUD_API_KEY: IBM Cloud API key.

#### Arguments:
--service-instance-id: PowerVS service instance id.

--bucket: Cloud Object Storage bucket name.

--bucket-region: Cloud Object Storage bucket location.

--object: Cloud Object Storage object name.

--accesskey: Cloud Object Storage HMAC access key.

--secretkey: Cloud Object Storage HMAC secret key.

--name: Name to PowerVS imported image.

--public-bucket: Cloud Object Storage public bucket.

--watch-timeout: watch timeout.

--pvs-storagetype: PowerVS Storage type, accepted values are [tier1, tier3]..


#### Example:
```shell
export IBMCLOUD_API_KEY=<api-key>
# import image using default storage type (service credential will be autogenerated):
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --object rhel-83-10032020.ova.gz --name <imagename> -r <region> --zone <zone>

# import image using default storage type with specifying the accesskey and secretkey explicitly:
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --object rhel-83-10032020.ova.gz --name <imagename> -r <region> --zone <zone> --accesskey <accesskey> --secretkey <secretkey>

# with user provided storage type:
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --pvs-storagetype <storagetype> --object rhel-83-10032020.ova.gz --name <imagename> -r <region> --zone <zone>

#import image from a public IBM Cloud Storage bucket:
capibmadm powervs image import --service-instance-id <service-instance-id> -b <bucketname> --object rhel-83-10032020.ova.gz --name <imagename> -r <region> --public-bucket --zone <zone>

```


### 2. capibmadm powervs image list

#### Usage:
List PowerVS images.
Expand Down
3 changes: 2 additions & 1 deletion docs/book/src/topics/capibmadm/powervs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
- [delete](/topics/capibmadm/powervs/port.html#2-capibmadm-powervs-port-delete)
- [list](/topics/capibmadm/powervs/port.html#3-capibmadm-powervs-port-list)
- [image](./image.md)
- [list](/topics/capibmadm/powervs/image.html#1-capibmadm-powervs-image-list)
- [import](/topics/capibmadm/powervs/image.html#1-capibmadm-powervs-image-import)
- [list](/topics/capibmadm/powervs/image.html#2-capibmadm-powervs-image-list)

0 comments on commit 0bbe9ec

Please sign in to comment.