Skip to content

Commit

Permalink
Allow image-upload to recover from PendingPopulation phase
Browse files Browse the repository at this point in the history
This commit fixes virtctl image-upload command so we allow recovering from PendingPopulation phase, as it did with WaitForFirstConsumer.

This means that, if an image-upload fails due to a DV being in PendingPopulation phase, we can call the command again after creating a consumer and the upload will continue as expected.

Signed-off-by: Alvaro Romero <alromero@redhat.com>
  • Loading branch information
alromeros committed Sep 5, 2023
1 parent 4937d96 commit a1ffd3c
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
16 changes: 15 additions & 1 deletion pkg/virtctl/imageupload/imageupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ const (
forceImmediateBindingAnnotation = "cdi.kubevirt.io/storage.bind.immediate.requested"
contentTypeAnnotation = "cdi.kubevirt.io/storage.contentType"
deleteAfterCompletionAnnotation = "cdi.kubevirt.io/storage.deleteAfterCompletion"
UsePopulatorAnnotation = "cdi.kubevirt.io/storage.usePopulator"
PVCPrimeNameAnnotation = "cdi.kubevirt.io/storage.populator.pvcPrime"

uploadReadyWaitInterval = 2 * time.Second

Expand Down Expand Up @@ -762,7 +764,7 @@ func getAndValidateUploadPVC(client kubecli.KubevirtClient, namespace, name stri
}

if !createPVC {
_, err = client.CdiClient().CdiV1beta1().DataVolumes(namespace).Get(context.Background(), name, metav1.GetOptions{})
dv, err := client.CdiClient().CdiV1beta1().DataVolumes(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
// When the PVC exists but the DV doesn't, there are two possible outcomes:
if k8serrors.IsNotFound(err) {
Expand All @@ -776,6 +778,18 @@ func getAndValidateUploadPVC(client kubecli.KubevirtClient, namespace, name stri
}
return nil, err
}
// When using populators, the upload is done on the PVC Prime. We need to check it instead.
if dv.Annotations[UsePopulatorAnnotation] == "true" {
pvcPrimeName, ok := pvc.Annotations[PVCPrimeNameAnnotation]
if !ok {
return nil, fmt.Errorf("Unable to get PVC Prime name")
}
pvc, err = client.CoreV1().PersistentVolumeClaims(namespace).Get(context.Background(), pvcPrimeName, metav1.GetOptions{})
if err != nil {
fmt.Printf("PVC %s/%s not found \n", namespace, name)
return nil, err
}
}
}

// for PVCs that exist, we ony want to use them if
Expand Down
52 changes: 52 additions & 0 deletions tests/storage/imageupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"kubevirt.io/kubevirt/tests/errorhandling"
execute "kubevirt.io/kubevirt/tests/exec"
"kubevirt.io/kubevirt/tests/flags"
"kubevirt.io/kubevirt/tests/framework/matcher"
"kubevirt.io/kubevirt/tests/libstorage"
)

Expand Down Expand Up @@ -254,6 +255,57 @@ var _ = SIGDescribe("[Serial]ImageUpload", Serial, func() {
)
})

Context("Upload fails when DV is in WFFC/PendingPopulation phase", func() {
It("but uploads after consumer is created", func() {
storageClass, exists := libstorage.GetRWOFileSystemStorageClass()
if !exists || !libstorage.IsStorageClassBindingModeWaitForFirstConsumer(storageClass) {
Skip("Skip no wffc storage class available")
}
defer deleteDataVolume("target-dv")

By("Upload image")
virtctlCmd := clientcmd.NewRepeatableVirtctlCommand(imageUploadCmd,
"dv", "target-dv",
namespaceArg, testsuite.GetTestNamespace(nil),
"--image-path", imagePath,
sizeArg, pvcSize,
"--storage-class", storageClass,
"--access-mode", "ReadWriteOnce",
insecureArg)

err := virtctlCmd()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("make sure the PVC is Bound, or use force-bind flag"))

By("Start VM")
vmi := tests.NewRandomVMIWithDataVolume("target-dv")
vmi, err = virtClient.VirtualMachineInstance(testsuite.GetTestNamespace(vmi)).Create(context.Background(), vmi)
Expect(err).ToNot(HaveOccurred())
defer func() {
err = virtClient.VirtualMachineInstance(testsuite.GetTestNamespace(vmi)).Delete(context.Background(), vmi.Name, &metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
}()

By("Wait for DV to be in UploadReady phase")
dataVolume, err := virtClient.CdiClient().CdiV1beta1().DataVolumes(testsuite.GetTestNamespace(nil)).Get(context.Background(), "target-dv", metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
libstorage.EventuallyDV(dataVolume, 240, matcher.BeInPhase(cdiv1.UploadReady))

By("Upload image, now should succeed")
virtctlCmd = clientcmd.NewRepeatableVirtctlCommand(imageUploadCmd,
"dv", "target-dv",
namespaceArg, testsuite.GetTestNamespace(nil),
"--image-path", imagePath,
sizeArg, pvcSize,
"--storage-class", storageClass,
"--access-mode", "ReadWriteOnce",
insecureArg)

Expect(virtctlCmd()).To(Succeed())
validateDataVolume("target-dv", storageClass)
})
})

Context("Create upload archive volume", func() {
var archivePath string

Expand Down

0 comments on commit a1ffd3c

Please sign in to comment.