Skip to content

Commit

Permalink
refactor virtctl image-upload args
Browse files Browse the repository at this point in the history
1.  legacy invocation (--pvc-name) should not create a DataVolume
2.  "virtctl image-upload pvc foo ..." will now create a PVC if does not exist

Signed-off-by: Michael Henriksen <[email protected]>
  • Loading branch information
mhenriks committed Aug 27, 2020
1 parent 4a9fd42 commit f6bc1a6
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 121 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module kubevirt.io/kubevirt

go 1.12

require (
github.com/Azure/go-autorest/autorest v0.9.1 // indirect
github.com/Azure/go-autorest/autorest/adal v0.6.0 // indirect
Expand Down
105 changes: 77 additions & 28 deletions pkg/virtctl/imageupload/imageupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"net/url"
"os"
"path"
"reflect"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -84,6 +85,7 @@ var (
uploadPodWaitSecs uint
blockVolume bool
noCreate bool
createPVC bool
)

// HTTPClientCreator is a function that creates http clients
Expand Down Expand Up @@ -141,16 +143,19 @@ func NewImageUploadCommand(clientConfig clientcmd.ClientConfig) *cobra.Command {

func usage() string {
usage := ` # Upload a local disk image to a newly created DataVolume:
{{ProgramName}} image-upload dv dv-name --size=10Gi --image-path=/images/fedora30.qcow2
{{ProgramName}} image-upload dv fedora-dv --size=10Gi --image-path=/images/fedora30.qcow2
# Upload a local disk image to an existing DataVolume
{{ProgramName}} image-upload dv dv-name --no-create --image-path=/images/fedora30.qcow2
{{ProgramName}} image-upload dv fedora-dv --no-create --image-path=/images/fedora30.qcow2
# Upload a local disk image to a newly created PersistentVolumeClaim
{{ProgramName}} image-upload pvc fedora-pvc --size=10Gi --image-path=/images/fedora30.qcow2
# Upload a local disk image to an existing PersistentVolumeClaim
{{ProgramName}} image-upload pvc pvc-name --image-path=/images/fedora30.qcow2
{{ProgramName}} image-upload pvc fedora-pvc --no-create --image-path=/images/fedora30.qcow2
# Upload to a DataVolume with explicit URL to CDI Upload Proxy
{{ProgramName}} image-upload dv dv-name --uploadproxy-url=https://cdi-uploadproxy.mycluster.com --image-path=/images/fedora30.qcow2`
{{ProgramName}} image-upload dv fedora-dv --uploadproxy-url=https://cdi-uploadproxy.mycluster.com --image-path=/images/fedora30.qcow2`
return usage
}

Expand All @@ -173,6 +178,8 @@ func parseArgs(args []string) error {
return fmt.Errorf("cannot use --pvc-name and args")
}

createPVC = true

return nil
}

Expand All @@ -182,8 +189,9 @@ func parseArgs(args []string) error {

switch strings.ToLower(args[0]) {
case "dv":
createPVC = false
case "pvc":
noCreate = true
createPVC = true
default:
return fmt.Errorf("invalid resource type %s", args[0])
}
Expand Down Expand Up @@ -221,15 +229,24 @@ func (c *command) run(cmd *cobra.Command, args []string) error {
}

if !noCreate && len(size) == 0 {
return fmt.Errorf("when creating DataVolume, the size must be specified")
return fmt.Errorf("when creating a resource, the size must be specified")
}

dv, err := createUploadDataVolume(virtClient, namespace, name, size, storageClass, accessMode, blockVolume)
if err != nil {
return err
var obj metav1.Object

if createPVC {
obj, err = createUploadPVC(virtClient, namespace, name, size, storageClass, accessMode, blockVolume)
if err != nil {
return err
}
} else {
obj, err = createUploadDataVolume(virtClient, namespace, name, size, storageClass, accessMode, blockVolume)
if err != nil {
return err
}
}

fmt.Printf("DataVolume %s/%s created\n", dv.Namespace, dv.Name)
fmt.Printf("%s %s/%s created\n", reflect.TypeOf(obj).Elem().Name(), obj.GetNamespace(), obj.GetName())
} else {
pvc, err = ensurePVCSupportsUpload(virtClient, pvc)
if err != nil {
Expand Down Expand Up @@ -453,9 +470,9 @@ func waitUploadProcessingComplete(client kubernetes.Interface, namespace, name s
}

func createUploadDataVolume(client kubecli.KubevirtClient, namespace, name, size, storageClass, accessMode string, blockVolume bool) (*cdiv1.DataVolume, error) {
quantity, err := resource.ParseQuantity(size)
pvcSpec, err := createPVCSpec(size, storageClass, accessMode, blockVolume)
if err != nil {
return nil, fmt.Errorf("validation failed for size=%s: %s", size, err)
return nil, err
}

dv := &cdiv1.DataVolume{
Expand All @@ -467,35 +484,67 @@ func createUploadDataVolume(client kubecli.KubevirtClient, namespace, name, size
Source: cdiv1.DataVolumeSource{
Upload: &cdiv1.DataVolumeSourceUpload{},
},
PVC: &v1.PersistentVolumeClaimSpec{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceStorage: quantity,
},
},
},
PVC: pvcSpec,
},
}

if storageClass != "" {
dv.Spec.PVC.StorageClassName = &storageClass
dv, err = client.CdiClient().CdiV1alpha1().DataVolumes(namespace).Create(dv)
if err != nil {
return nil, err
}

if accessMode != "" {
dv.Spec.PVC.AccessModes = []v1.PersistentVolumeAccessMode{v1.PersistentVolumeAccessMode(accessMode)}
return dv, nil
}

func createUploadPVC(client kubernetes.Interface, namespace, name, size, storageClass, accessMode string, blockVolume bool) (*v1.PersistentVolumeClaim, error) {
pvcSpec, err := createPVCSpec(size, storageClass, accessMode, blockVolume)
if err != nil {
return nil, err
}

if blockVolume {
volMode := v1.PersistentVolumeBlock
dv.Spec.PVC.VolumeMode = &volMode
pvc := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Annotations: map[string]string{
uploadRequestAnnotation: "",
},
},
Spec: *pvcSpec,
}

dv, err = client.CdiClient().CdiV1alpha1().DataVolumes(namespace).Create(dv)
pvc, err = client.CoreV1().PersistentVolumeClaims(namespace).Create(pvc)
if err != nil {
return nil, err
}

return dv, nil
return pvc, nil
}

func createPVCSpec(size, storageClass, accessMode string, blockVolume bool) (*v1.PersistentVolumeClaimSpec, error) {
quantity, err := resource.ParseQuantity(size)
if err != nil {
return nil, fmt.Errorf("validation failed for size=%s: %s", size, err)
}

spec := &v1.PersistentVolumeClaimSpec{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceStorage: quantity,
},
},
}

if accessMode != "" {
spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.PersistentVolumeAccessMode(accessMode)}
}

if blockVolume {
volMode := v1.PersistentVolumeBlock
spec.VolumeMode = &volMode
}

return spec, nil
}

func ensurePVCSupportsUpload(client kubernetes.Interface, pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
Expand Down
Loading

0 comments on commit f6bc1a6

Please sign in to comment.