Skip to content

Commit d278698

Browse files
authored
Merge pull request #485 from zvikorn/upload-dv
Orchestrate upload using a DataVolume
2 parents 949f507 + 1eaf3a5 commit d278698

File tree

6 files changed

+203
-4
lines changed

6 files changed

+203
-4
lines changed
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: cdi.kubevirt.io/v1alpha1
2+
kind: DataVolume
3+
metadata:
4+
name: upload-datavolume
5+
spec:
6+
source:
7+
upload:
8+
target: {}
9+
pvc:
10+
#the storageClassName is optional, if missing we use the default storage class.
11+
#storageClassName: "hostpath"
12+
accessModes:
13+
- ReadWriteOnce
14+
resources:
15+
requests:
16+
storage: 500Mi
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: upload.cdi.kubevirt.io/v1alpha1
2+
kind: UploadTokenRequest
3+
metadata:
4+
name: upload-datavolume
5+
namespace: default
6+
spec:
7+
pvcName: upload-datavolume

pkg/apis/datavolumecontroller/v1alpha1/types.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ type DataVolumeSpec struct {
4242

4343
// DataVolumeSource represents the source for our Data Volume, this can be HTTP, S3 or an existing PVC
4444
type DataVolumeSource struct {
45-
HTTP *DataVolumeSourceHTTP `json:"http,omitempty"`
46-
S3 *DataVolumeSourceS3 `json:"s3,omitempty"`
47-
PVC *DataVolumeSourcePVC `json:"pvc,omitempty"`
45+
HTTP *DataVolumeSourceHTTP `json:"http,omitempty"`
46+
S3 *DataVolumeSourceS3 `json:"s3,omitempty"`
47+
PVC *DataVolumeSourcePVC `json:"pvc,omitempty"`
48+
UPLOAD *DataVolumeSourceUpload `json:"upload,omitempty"`
4849
}
4950

5051
// DataVolumeSourcePVC provides the parameters to create a Data Volume from an existing PVC
@@ -53,6 +54,11 @@ type DataVolumeSourcePVC struct {
5354
Name string `json:"name,omitempty"`
5455
}
5556

57+
// DataVolumeSourceUpload provides the parameters to create a Data Volume by uploading the source
58+
type DataVolumeSourceUpload struct {
59+
//Target string `json:"shouldUpload,omitempty"`
60+
}
61+
5662
// DataVolumeSourceS3 provides the parameters to create a Data Volume from an S3 source
5763
type DataVolumeSourceS3 struct {
5864
//URL is the url of the S3 source
@@ -109,6 +115,12 @@ const (
109115
// CloneInProgress represents a data volume with a current phase of CloneInProgress
110116
CloneInProgress DataVolumePhase = "CloneInProgress"
111117

118+
// UploadScheduled represents a data volume with a current phase of UploadScheduled
119+
UploadScheduled DataVolumePhase = "UploadScheduled"
120+
121+
// UploadReady represents a data volume with a current phase of UploadReady
122+
UploadReady DataVolumePhase = "UploadReady"
123+
112124
// Succeeded represents a DataVolumePhase of Succeeded
113125
Succeeded DataVolumePhase = "Succeeded"
114126
// Failed represents a DataVolumePhase of Failed

pkg/apis/datavolumecontroller/v1alpha1/zz_generated.deepcopy.go

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/datavolume-controller.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,24 @@ func (c *DataVolumeController) updateCloneStatusPhase(pvc *corev1.PersistentVolu
334334
}
335335
}
336336

337+
func (c *DataVolumeController) updateUploadStatusPhase(pvc *corev1.PersistentVolumeClaim, dataVolumeCopy *cdiv1.DataVolume) {
338+
phase, ok := pvc.Annotations[AnnPodPhase]
339+
if ok {
340+
switch phase {
341+
case string(corev1.PodPending):
342+
// TODO: Use a more generic Scheduled, like maybe TransferScheduled.
343+
dataVolumeCopy.Status.Phase = cdiv1.UploadScheduled
344+
case string(corev1.PodRunning):
345+
// TODO: Use a more generic In Progess, like maybe TransferInProgress.
346+
dataVolumeCopy.Status.Phase = cdiv1.UploadReady
347+
case string(corev1.PodFailed):
348+
dataVolumeCopy.Status.Phase = cdiv1.Failed
349+
case string(corev1.PodSucceeded):
350+
dataVolumeCopy.Status.Phase = cdiv1.Succeeded
351+
}
352+
}
353+
}
354+
337355
func (c *DataVolumeController) updateDataVolumeStatus(dataVolume *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) error {
338356
dataVolumeCopy := dataVolume.DeepCopy()
339357
var err error
@@ -370,6 +388,11 @@ func (c *DataVolumeController) updateDataVolumeStatus(dataVolume *cdiv1.DataVolu
370388
dataVolumeCopy.Status.Phase = cdiv1.CloneScheduled
371389
c.updateCloneStatusPhase(pvc, dataVolumeCopy)
372390
}
391+
_, ok = pvc.Annotations[AnnUploadRequest]
392+
if ok {
393+
dataVolumeCopy.Status.Phase = cdiv1.UploadScheduled
394+
c.updateUploadStatusPhase(pvc, dataVolumeCopy)
395+
}
373396

374397
case corev1.ClaimLost:
375398
dataVolumeCopy.Status.Phase = cdiv1.Failed
@@ -493,7 +516,8 @@ func newPersistentVolumeClaim(dataVolume *cdiv1.DataVolume) (*corev1.PersistentV
493516
} else {
494517
annotations[AnnCloneRequest] = dataVolume.Namespace + "/" + dataVolume.Spec.Source.PVC.Name
495518
}
496-
519+
} else if dataVolume.Spec.Source.UPLOAD != nil {
520+
annotations[AnnUploadRequest] = ""
497521
} else {
498522
return nil, errors.Errorf("no source set for datavolume")
499523
}

pkg/controller/datavolume-controller_test.go

+119
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,22 @@ func newCloneDataVolume(name string) *cdiv1.DataVolume {
106106
}
107107
}
108108

109+
func newUploadDataVolume(name string) *cdiv1.DataVolume {
110+
return &cdiv1.DataVolume{
111+
TypeMeta: metav1.TypeMeta{APIVersion: cdiv1.SchemeGroupVersion.String()},
112+
ObjectMeta: metav1.ObjectMeta{
113+
Name: name,
114+
Namespace: metav1.NamespaceDefault,
115+
},
116+
Spec: cdiv1.DataVolumeSpec{
117+
Source: cdiv1.DataVolumeSource{
118+
UPLOAD: &cdiv1.DataVolumeSourceUpload{},
119+
},
120+
PVC: &corev1.PersistentVolumeClaimSpec{},
121+
},
122+
}
123+
}
124+
109125
func (f *fixture) newController() (*DataVolumeController, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) {
110126
f.client = fake.NewSimpleClientset(f.objects...)
111127
f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...)
@@ -543,3 +559,106 @@ func TestCloneClaimLost(t *testing.T) {
543559
f.expectUpdateDataVolumeStatusAction(result)
544560
f.run(getKey(dataVolume, t))
545561
}
562+
563+
// Upload tests
564+
func TestUploadScheduled(t *testing.T) {
565+
f := newFixture(t)
566+
dataVolume := newUploadDataVolume("upload-datavolume")
567+
pvc, _ := newPersistentVolumeClaim(dataVolume)
568+
569+
dataVolume.Status.Phase = cdiv1.Pending
570+
pvc.Status.Phase = corev1.ClaimBound
571+
pvc.Annotations[AnnUploadRequest] = ""
572+
573+
f.dataVolumeLister = append(f.dataVolumeLister, dataVolume)
574+
f.objects = append(f.objects, dataVolume)
575+
f.pvcLister = append(f.pvcLister, pvc)
576+
f.kubeobjects = append(f.kubeobjects, pvc)
577+
578+
result := dataVolume.DeepCopy()
579+
result.Status.Phase = cdiv1.UploadScheduled
580+
f.expectUpdateDataVolumeStatusAction(result)
581+
f.run(getKey(dataVolume, t))
582+
}
583+
584+
func TestUploadReady(t *testing.T) {
585+
f := newFixture(t)
586+
dataVolume := newUploadDataVolume("upload-datavolume")
587+
pvc, _ := newPersistentVolumeClaim(dataVolume)
588+
589+
dataVolume.Status.Phase = cdiv1.Pending
590+
pvc.Status.Phase = corev1.ClaimBound
591+
pvc.Annotations[AnnUploadRequest] = ""
592+
pvc.Annotations[AnnPodPhase] = "Running"
593+
594+
f.dataVolumeLister = append(f.dataVolumeLister, dataVolume)
595+
f.objects = append(f.objects, dataVolume)
596+
f.pvcLister = append(f.pvcLister, pvc)
597+
f.kubeobjects = append(f.kubeobjects, pvc)
598+
599+
result := dataVolume.DeepCopy()
600+
result.Status.Phase = cdiv1.UploadReady
601+
f.expectUpdateDataVolumeStatusAction(result)
602+
f.run(getKey(dataVolume, t))
603+
}
604+
605+
func TestUploadSucceeded(t *testing.T) {
606+
f := newFixture(t)
607+
dataVolume := newUploadDataVolume("upload-datavolume")
608+
pvc, _ := newPersistentVolumeClaim(dataVolume)
609+
610+
dataVolume.Status.Phase = cdiv1.Pending
611+
pvc.Status.Phase = corev1.ClaimBound
612+
pvc.Annotations[AnnUploadRequest] = ""
613+
pvc.Annotations[AnnPodPhase] = "Succeeded"
614+
615+
f.dataVolumeLister = append(f.dataVolumeLister, dataVolume)
616+
f.objects = append(f.objects, dataVolume)
617+
f.pvcLister = append(f.pvcLister, pvc)
618+
f.kubeobjects = append(f.kubeobjects, pvc)
619+
620+
result := dataVolume.DeepCopy()
621+
result.Status.Phase = cdiv1.Succeeded
622+
f.expectUpdateDataVolumeStatusAction(result)
623+
f.run(getKey(dataVolume, t))
624+
}
625+
626+
func TestUploadPodFailed(t *testing.T) {
627+
f := newFixture(t)
628+
dataVolume := newCloneDataVolume("upload-datavolume")
629+
pvc, _ := newPersistentVolumeClaim(dataVolume)
630+
631+
dataVolume.Status.Phase = cdiv1.Pending
632+
pvc.Status.Phase = corev1.ClaimBound
633+
pvc.Annotations[AnnUploadRequest] = ""
634+
pvc.Annotations[AnnPodPhase] = "Failed"
635+
636+
f.dataVolumeLister = append(f.dataVolumeLister, dataVolume)
637+
f.objects = append(f.objects, dataVolume)
638+
f.pvcLister = append(f.pvcLister, pvc)
639+
f.kubeobjects = append(f.kubeobjects, pvc)
640+
641+
result := dataVolume.DeepCopy()
642+
result.Status.Phase = cdiv1.Failed
643+
f.expectUpdateDataVolumeStatusAction(result)
644+
f.run(getKey(dataVolume, t))
645+
}
646+
647+
func TestUploadClaimLost(t *testing.T) {
648+
f := newFixture(t)
649+
dataVolume := newUploadDataVolume("upload-datavolume")
650+
pvc, _ := newPersistentVolumeClaim(dataVolume)
651+
652+
dataVolume.Status.Phase = cdiv1.Pending
653+
pvc.Status.Phase = corev1.ClaimLost
654+
655+
f.dataVolumeLister = append(f.dataVolumeLister, dataVolume)
656+
f.objects = append(f.objects, dataVolume)
657+
f.pvcLister = append(f.pvcLister, pvc)
658+
f.kubeobjects = append(f.kubeobjects, pvc)
659+
660+
result := dataVolume.DeepCopy()
661+
result.Status.Phase = cdiv1.Failed
662+
f.expectUpdateDataVolumeStatusAction(result)
663+
f.run(getKey(dataVolume, t))
664+
}

0 commit comments

Comments
 (0)