forked from kubernetes-sigs/cluster-api-provider-ibmcloud
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added image import cmd (kubernetes-sigs#1216)
- Loading branch information
1 parent
c8f7c1a
commit 0bbe9ec
Showing
5 changed files
with
240 additions
and
2 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters