Skip to content

Commit 8a6654c

Browse files
impl
Signed-off-by: Yaroslav Borbat <[email protected]>
1 parent 078aef1 commit 8a6654c

File tree

14 files changed

+161
-59
lines changed

14 files changed

+161
-59
lines changed

api/core/v1alpha2/vdcondition/condition.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ the `InUse` condition's reason to `AttachedToVirtualMachine`.
155155
const (
156156
// UsedForImageCreation indicates that the VirtualDisk is used for create image.
157157
UsedForImageCreation InUseReason = "UsedForImageCreation"
158+
// UsedForDataExport indicates that the VirtualDisk is used for data export.
159+
UsedForDataExport InUseReason = "UsedForDataExport"
158160
// AttachedToVirtualMachine indicates that the VirtualDisk is attached to VirtualMachine.
159161
AttachedToVirtualMachine InUseReason = "AttachedToVirtualMachine"
160162
// NotInUse indicates that VirtualDisk free for use.

api/core/v1alpha2/vdscondition/condition.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const (
6565
FileSystemFreezing VirtualDiskSnapshotReadyReason = "FileSystemFreezing"
6666
// Snapshotting signifies that the `VirtualDiskSnapshot` resource is in the process of taking a snapshot of the virtual disk.
6767
Snapshotting VirtualDiskSnapshotReadyReason = "Snapshotting"
68+
// Exporting signifies that the `VirtualDiskSnapshot` resource is in the process of exporting the snapshot to a persistent volume claim.
69+
Exporting VirtualDiskSnapshotReadyReason = "Exporting"
6870
// VirtualDiskSnapshotReady signifies that the snapshot process is complete and the `VirtualDiskSnapshot` is ready for use.
6971
VirtualDiskSnapshotReady VirtualDiskSnapshotReadyReason = "VirtualDiskSnapshotReady"
7072
// VirtualDiskSnapshotFailed signifies that the snapshot process has failed.

api/core/v1alpha2/virtual_disk.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,9 @@ type VirtualDiskList struct {
196196
// * `Resizing`: The process of resource resizing is in progress.
197197
// * `Failed`: There was an error when creating the resource.
198198
// * `PVCLost`: The child PVC of the resource is missing. The resource cannot be used.
199+
// * `Exporting`: The child PV of the resource is in the process of exporting.
199200
// * `Terminating`: The resource is being deleted.
200-
// +kubebuilder:validation:Enum:={Pending,Provisioning,WaitForUserUpload,WaitForFirstConsumer,Ready,Resizing,Failed,PVCLost,Terminating}
201+
// +kubebuilder:validation:Enum:={Pending,Provisioning,WaitForUserUpload,WaitForFirstConsumer,Ready,Resizing,Failed,PVCLost,Exporting,Terminating}
201202
type DiskPhase string
202203

203204
const (
@@ -209,5 +210,6 @@ const (
209210
DiskResizing DiskPhase = "Resizing"
210211
DiskFailed DiskPhase = "Failed"
211212
DiskLost DiskPhase = "PVCLost"
213+
DiskExporting DiskPhase = "Exporting"
212214
DiskTerminating DiskPhase = "Terminating"
213215
)

crds/doc-ru-virtualdisks.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ spec:
199199
* `Resizing` — идёт процесс увеличения размера диска;
200200
* `Failed` — при создании ресурса произошла ошибка;
201201
* `PVCLost` — дочерний PVC ресурса отсутствует. Ресурс не может быть использован;
202+
* `Exporting` - дочерний PV ресурс находится в процессе экспорта;
202203
* `Terminating` - ресурс находится в процессе удаления.
203204
progress:
204205
description: |

crds/virtualdisks.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ spec:
381381
* `Resizing`: The process of resource resizing is in progress.
382382
* `Failed`: There was an error when creating the resource.
383383
* `PVCLost`: The child PVC of the resource is missing. The resource cannot be used.
384+
* `Exporting`: The child PV of the resource is in the process of exporting.
384385
* `Terminating`: The resource is being deleted.
385386
enum:
386387
- Pending
@@ -391,6 +392,7 @@ spec:
391392
- Resizing
392393
- Failed
393394
- PVCLost
395+
- Exporting
394396
- Terminating
395397
type: string
396398
progress:

images/virtualization-artifact/pkg/common/annotations/annotations.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,19 @@ const (
125125
// AnnNodeCpuFeature is the Kubevirt annotation for CPU feature.
126126
AnnNodeCPUFeature = "cpu-feature.node.virtualization.deckhouse.io/"
127127

128-
// AnnExportInProgress is the annotation for indicating that export is in progress.
129-
AnnExportInProgress = "storage.deckhouse.io/export-in-progress"
128+
// AnnDataExportRequest is the annotation for indicating that export requested.
129+
AnnDataExportRequest = "storage.deckhouse.io/data-export-request"
130+
131+
// TODO: remove deprecated annotations in the v1 version.
132+
// AnnStorageClassName is the annotation for indicating that storage class name. (USED IN STORAGE)
133+
AnnStorageClassName = AnnAPIGroupV + "/storage-class-name"
134+
AnnStorageClassNameDeprecated = "storageClass"
135+
// AnnVolumeMode is the annotation for indicating that volume mode. (USED IN STORAGE)
136+
AnnVolumeMode = AnnAPIGroupV + "/volume-mode"
137+
AnnVolumeModeDeprecated = "volumeMode"
138+
// AnnAccessMode is the annotation for indicating that access mode. (USED IN STORAGE)
139+
AnnAccessModes = AnnAPIGroupV + "/access-mode"
140+
AnnAccessModesDeprecated = "accessModes"
130141

131142
// AppLabel is the app name label.
132143
AppLabel = "app"

images/virtualization-artifact/pkg/controller/cvi/internal/source/object_ref_vdsnapshot.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,20 @@ func (ds ObjectRefVirtualDiskSnapshot) Sync(ctx context.Context, cvi *virtv2.Clu
132132

133133
pvcKey := supplements.NewGenerator(annotations.CVIShortName, cvi.Name, cvi.Spec.DataSource.ObjectRef.Namespace, cvi.UID).PersistentVolumeClaim()
134134

135-
storageClassName := vs.Annotations["storageClass"]
136-
volumeMode := vs.Annotations["volumeMode"]
137-
accessModesStr := strings.Split(vs.Annotations["accessModes"], ",")
135+
storageClassName := vs.Annotations[annotations.AnnStorageClassName]
136+
if storageClassName == "" {
137+
storageClassName = vs.Annotations[annotations.AnnStorageClassNameDeprecated]
138+
}
139+
volumeMode := vs.Annotations[annotations.AnnVolumeMode]
140+
if volumeMode == "" {
141+
volumeMode = vs.Annotations[annotations.AnnVolumeModeDeprecated]
142+
}
143+
accessModesRaw := vs.Annotations[annotations.AnnAccessModes]
144+
if accessModesRaw == "" {
145+
accessModesRaw = vs.Annotations[annotations.AnnAccessModesDeprecated]
146+
}
147+
148+
accessModesStr := strings.Split(accessModesRaw, ",")
138149
accessModes := make([]corev1.PersistentVolumeAccessMode, 0, len(accessModesStr))
139150
for _, accessModeStr := range accessModesStr {
140151
accessModes = append(accessModes, corev1.PersistentVolumeAccessMode(accessModeStr))

images/virtualization-artifact/pkg/controller/vd/internal/inuse.go

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"fmt"
2222
"slices"
23-
"time"
2423

2524
corev1 "k8s.io/api/core/v1"
2625
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -30,6 +29,7 @@ import (
3029
"sigs.k8s.io/controller-runtime/pkg/client"
3130
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3231

32+
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
3333
"github.com/deckhouse/virtualization-controller/pkg/common/object"
3434
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
3535
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
@@ -49,59 +49,50 @@ func NewInUseHandler(client client.Client) *InUseHandler {
4949
}
5050

5151
func (h InUseHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (reconcile.Result, error) {
52-
inUseCondition, ok := conditions.GetCondition(vdcondition.InUseType, vd.Status.Conditions)
53-
if !ok {
54-
cb := conditions.NewConditionBuilder(vdcondition.InUseType).
55-
Status(metav1.ConditionUnknown).
56-
Reason(conditions.ReasonUnknown).
57-
Generation(vd.Generation)
58-
conditions.SetCondition(cb, &vd.Status.Conditions)
59-
inUseCondition = cb.Condition()
60-
}
61-
6252
err := h.updateAttachedVirtualMachines(ctx, vd)
6353
if err != nil {
6454
return reconcile.Result{}, err
6555
}
6656

67-
usedByVM, usedByImage := false, false
57+
var (
58+
usedByVM bool
59+
usedByImage bool
60+
usedByDataExport bool
61+
)
6862

69-
if inUseCondition.Reason != vdcondition.UsedForImageCreation.String() {
70-
usedByVM = h.checkUsageByVM(vd)
71-
72-
if !usedByVM {
73-
usedByImage, err = h.checkImageUsage(ctx, vd)
74-
if err != nil {
75-
return reconcile.Result{}, err
76-
}
77-
}
78-
} else {
63+
usedByVM = h.checkUsageByVM(vd)
64+
if !usedByVM {
7965
usedByImage, err = h.checkImageUsage(ctx, vd)
8066
if err != nil {
8167
return reconcile.Result{}, err
8268
}
83-
84-
if !usedByImage {
85-
usedByVM = h.checkUsageByVM(vd)
69+
}
70+
if !usedByVM && !usedByImage {
71+
usedByDataExport, err = h.checkDataExportUsage(ctx, vd)
72+
if err != nil {
73+
return reconcile.Result{}, err
8674
}
8775
}
8876

89-
cb := conditions.NewConditionBuilder(vdcondition.InUseType)
77+
cb := conditions.NewConditionBuilder(vdcondition.InUseType).Generation(vd.Generation)
9078
switch {
9179
case usedByVM:
92-
cb.Generation(vd.Generation).
80+
cb.
9381
Status(metav1.ConditionTrue).
9482
Reason(vdcondition.AttachedToVirtualMachine).
95-
Message("").
96-
LastTransitionTime(time.Now())
83+
Message("")
9784
case usedByImage:
98-
cb.Generation(vd.Generation).
85+
cb.
9986
Status(metav1.ConditionTrue).
10087
Reason(vdcondition.UsedForImageCreation).
101-
Message("").
102-
LastTransitionTime(time.Now())
88+
Message("")
89+
case usedByDataExport:
90+
cb.
91+
Status(metav1.ConditionTrue).
92+
Reason(vdcondition.UsedForDataExport).
93+
Message("")
10394
default:
104-
cb.Generation(vd.Generation).
95+
cb.
10596
Status(metav1.ConditionFalse).
10697
Reason(vdcondition.NotInUse).
10798
Message("")
@@ -121,6 +112,23 @@ func (h InUseHandler) isVDAttachedToVM(vdName string, vm virtv2.VirtualMachine)
121112
return false
122113
}
123114

115+
func (h InUseHandler) checkDataExportUsage(ctx context.Context, vd *virtv2.VirtualDisk) (bool, error) {
116+
pvcName := vd.Status.Target.PersistentVolumeClaim
117+
if pvcName == "" {
118+
return false, nil
119+
}
120+
121+
pvc, err := object.FetchObject(ctx, types.NamespacedName{Name: pvcName, Namespace: vd.Namespace}, h.client, &corev1.PersistentVolumeClaim{})
122+
if err != nil {
123+
return false, fmt.Errorf("fetch pvc: %w", err)
124+
}
125+
if pvc == nil {
126+
return false, nil
127+
}
128+
129+
return pvc.GetAnnotations()[annotations.AnnDataExportRequest] == "true", nil
130+
}
131+
124132
func (h InUseHandler) checkImageUsage(ctx context.Context, vd *virtv2.VirtualDisk) (bool, error) {
125133
// If disk is not ready, it cannot be used for create image
126134
if vd.Status.Phase != virtv2.DiskReady {

images/virtualization-artifact/pkg/controller/vd/internal/inuse_test.go

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@ package internal
1818

1919
import (
2020
"context"
21-
"time"
2221

2322
. "github.com/onsi/ginkgo/v2"
2423
. "github.com/onsi/gomega"
24+
corev1 "k8s.io/api/core/v1"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/apimachinery/pkg/runtime"
2727
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2828
virtv1 "kubevirt.io/api/core/v1"
2929
ctrl "sigs.k8s.io/controller-runtime"
3030
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3131

32+
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
3233
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
3334
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
3435
"github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition"
@@ -602,7 +603,6 @@ var _ = Describe("InUseHandler", func() {
602603

603604
Context("when VirtualDisk is used by VirtualMachine after create image", func() {
604605
It("must set status True and reason AllowedForVirtualMachineUsage", func() {
605-
startTime := metav1.Time{Time: time.Now()}
606606
vd := &virtv2.VirtualDisk{
607607
ObjectMeta: metav1.ObjectMeta{
608608
Name: "test-vd",
@@ -611,10 +611,9 @@ var _ = Describe("InUseHandler", func() {
611611
Status: virtv2.VirtualDiskStatus{
612612
Conditions: []metav1.Condition{
613613
{
614-
Type: vdcondition.InUseType.String(),
615-
Reason: vdcondition.UsedForImageCreation.String(),
616-
Status: metav1.ConditionTrue,
617-
LastTransitionTime: startTime,
614+
Type: vdcondition.InUseType.String(),
615+
Reason: vdcondition.UsedForImageCreation.String(),
616+
Status: metav1.ConditionTrue,
618617
},
619618
},
620619
},
@@ -647,7 +646,6 @@ var _ = Describe("InUseHandler", func() {
647646
Expect(cond).ToNot(BeNil())
648647
Expect(cond.Status).To(Equal(metav1.ConditionTrue))
649648
Expect(cond.Reason).To(Equal(vdcondition.AttachedToVirtualMachine.String()))
650-
Expect(cond.LastTransitionTime).ToNot(Equal(startTime))
651649
})
652650
})
653651

@@ -767,4 +765,44 @@ var _ = Describe("InUseHandler", func() {
767765
Expect(cond.Reason).To(Equal(vdcondition.NotInUse.String()))
768766
})
769767
})
768+
Context("when VirtualDisk is used by DataExport", func() {
769+
It("must set status True and reason UsedForDataExport", func() {
770+
vd := &virtv2.VirtualDisk{
771+
ObjectMeta: metav1.ObjectMeta{
772+
Name: "test-vd",
773+
Namespace: "default",
774+
},
775+
Status: virtv2.VirtualDiskStatus{
776+
Conditions: []metav1.Condition{},
777+
Target: virtv2.DiskTarget{
778+
PersistentVolumeClaim: "test-pvc",
779+
},
780+
},
781+
}
782+
pvc := &corev1.PersistentVolumeClaim{
783+
ObjectMeta: metav1.ObjectMeta{
784+
Name: "test-pvc",
785+
Namespace: "default",
786+
Annotations: map[string]string{
787+
annotations.AnnDataExportRequest: "true",
788+
},
789+
},
790+
Status: corev1.PersistentVolumeClaimStatus{
791+
Phase: corev1.ClaimBound,
792+
},
793+
}
794+
795+
k8sClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(vd, pvc).Build()
796+
handler = NewInUseHandler(k8sClient)
797+
798+
result, err := handler.Handle(ctx, vd)
799+
Expect(err).ToNot(HaveOccurred())
800+
Expect(result).To(Equal(ctrl.Result{}))
801+
802+
cond, _ := conditions.GetCondition(vdcondition.InUseType, vd.Status.Conditions)
803+
Expect(cond).ToNot(BeNil())
804+
Expect(cond.Status).To(Equal(metav1.ConditionTrue))
805+
Expect(cond.Reason).To(Equal(vdcondition.UsedForDataExport.String()))
806+
})
807+
})
770808
})

images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,12 @@ func setPhaseConditionForFinishedDisk(
113113
Reason(vdcondition.Lost).
114114
Message(fmt.Sprintf("PVC %s not found.", supgen.PersistentVolumeClaim().String()))
115115
case pvc.Status.Phase == corev1.ClaimLost:
116-
newPhase = virtv2.DiskLost
117116
cb.Status(metav1.ConditionFalse)
118-
if pvc.GetAnnotations()[annotations.AnnExportInProgress] == "true" {
117+
if pvc.GetAnnotations()[annotations.AnnDataExportRequest] == "true" {
118+
newPhase = virtv2.DiskExporting
119119
cb.Reason(vdcondition.Exporting).Message("PV is being exported")
120120
} else {
121+
newPhase = virtv2.DiskLost
121122
cb.Reason(vdcondition.Lost).Message(fmt.Sprintf("PV %s not found.", pvc.Spec.VolumeName))
122123
}
123124
default:

0 commit comments

Comments
 (0)