Skip to content

Commit 2ad4caa

Browse files
committed
fix(vd): fix issues with storage class condition display
Signed-off-by: Isteb4k <dmitry.rakitin@flant.com>
1 parent 5612507 commit 2ad4caa

28 files changed

Lines changed: 424 additions & 462 deletions
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright 2025 Flant JSC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package service
18+
19+
import (
20+
"context"
21+
"sort"
22+
23+
corev1 "k8s.io/api/core/v1"
24+
storagev1 "k8s.io/api/storage/v1"
25+
"k8s.io/apimachinery/pkg/types"
26+
"sigs.k8s.io/controller-runtime/pkg/client"
27+
28+
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
29+
"github.com/deckhouse/virtualization-controller/pkg/common/object"
30+
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
31+
)
32+
33+
type BaseStorageClassService struct {
34+
client client.Client
35+
}
36+
37+
func NewBaseStorageClassService(client client.Client) *BaseStorageClassService {
38+
return &BaseStorageClassService{client: client}
39+
}
40+
41+
func (s BaseStorageClassService) GetDefaultStorageClass(ctx context.Context) (*storagev1.StorageClass, error) {
42+
var scs storagev1.StorageClassList
43+
err := s.client.List(ctx, &scs, &client.ListOptions{})
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
var defaultClasses []*storagev1.StorageClass
49+
for idx := range scs.Items {
50+
if scs.Items[idx].Annotations[annotations.AnnDefaultStorageClass] == "true" {
51+
defaultClasses = append(defaultClasses, &scs.Items[idx])
52+
}
53+
}
54+
55+
if len(defaultClasses) == 0 {
56+
return nil, ErrDefaultStorageClassNotFound
57+
}
58+
59+
// Primary sort by creation timestamp, newest first
60+
// Secondary sort by class name, ascending order
61+
sort.Slice(defaultClasses, func(i, j int) bool {
62+
if defaultClasses[i].CreationTimestamp.UnixNano() == defaultClasses[j].CreationTimestamp.UnixNano() {
63+
return defaultClasses[i].Name < defaultClasses[j].Name
64+
}
65+
return defaultClasses[i].CreationTimestamp.UnixNano() > defaultClasses[j].CreationTimestamp.UnixNano()
66+
})
67+
68+
return defaultClasses[0], nil
69+
}
70+
71+
func (s BaseStorageClassService) GetStorageClass(ctx context.Context, scName string) (*storagev1.StorageClass, error) {
72+
return object.FetchObject(ctx, types.NamespacedName{Name: scName}, s.client, &storagev1.StorageClass{})
73+
}
74+
75+
func (s BaseStorageClassService) GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) {
76+
return object.FetchObject(ctx, sup.PersistentVolumeClaim(), s.client, &corev1.PersistentVolumeClaim{})
77+
}

images/virtualization-artifact/pkg/controller/service/disk_service.go

Lines changed: 20 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ import (
2222
"errors"
2323
"fmt"
2424
"slices"
25-
"sort"
2625
"strconv"
2726
"strings"
2827

2928
vsv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1"
3029
corev1 "k8s.io/api/core/v1"
31-
storev1 "k8s.io/api/storage/v1"
30+
storagev1 "k8s.io/api/storage/v1"
3231
k8serrors "k8s.io/apimachinery/pkg/api/errors"
3332
"k8s.io/apimachinery/pkg/api/resource"
3433
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -73,12 +72,16 @@ func NewDiskService(
7372
func (s DiskService) Start(
7473
ctx context.Context,
7574
pvcSize resource.Quantity,
76-
storageClass *string,
75+
sc *storagev1.StorageClass,
7776
source *cdiv1.DataVolumeSource,
7877
obj ObjectKind,
7978
sup *supplements.Generator,
8079
opts ...Option,
8180
) error {
81+
if sc == nil {
82+
return errors.New("cannot create DataVolume: StorageClass must not be nil")
83+
}
84+
8285
dvBuilder := kvbuilder.NewDV(sup.DataVolume())
8386
dvBuilder.SetDataSource(source)
8487
dvBuilder.SetOwnerRef(obj, obj.GroupVersionKind())
@@ -95,17 +98,12 @@ func (s DiskService) Start(
9598
}
9699
}
97100

98-
sc, err := s.GetStorageClass(ctx, storageClass)
99-
if err != nil {
100-
return fmt.Errorf("get storage class: %w", err)
101-
}
102-
103101
volumeMode, accessMode, err := s.GetVolumeAndAccessModes(ctx, sc)
104102
if err != nil {
105103
return fmt.Errorf("get volume and access modes: %w", err)
106104
}
107105

108-
dvBuilder.SetPVC(storageClass, pvcSize, accessMode, volumeMode)
106+
dvBuilder.SetPVC(&sc.Name, pvcSize, accessMode, volumeMode)
109107

110108
if s.isImmediateBindingMode(sc) {
111109
dvBuilder.SetImmediate()
@@ -129,7 +127,7 @@ func (s DiskService) Start(
129127
return supplements.EnsureForDataVolume(ctx, s.client, sup, dvBuilder.GetResource(), s.dvcrSettings)
130128
}
131129

132-
func (s DiskService) GetVolumeAndAccessModes(ctx context.Context, sc *storev1.StorageClass) (corev1.PersistentVolumeMode, corev1.PersistentVolumeAccessMode, error) {
130+
func (s DiskService) GetVolumeAndAccessModes(ctx context.Context, sc *storagev1.StorageClass) (corev1.PersistentVolumeMode, corev1.PersistentVolumeAccessMode, error) {
133131
if sc == nil {
134132
return "", "", errors.New("storage class is nil")
135133
}
@@ -163,14 +161,13 @@ func (s DiskService) GetVolumeAndAccessModes(ctx context.Context, sc *storev1.St
163161
func (s DiskService) StartImmediate(
164162
ctx context.Context,
165163
pvcSize resource.Quantity,
166-
storageClass *string,
164+
sc *storagev1.StorageClass,
167165
source *cdiv1.DataVolumeSource,
168166
obj ObjectKind,
169167
sup *supplements.Generator,
170168
) error {
171-
sc, err := s.GetStorageClass(ctx, storageClass)
172-
if err != nil {
173-
return err
169+
if sc == nil {
170+
return errors.New("cannot create DataVolume: StorageClass must not be nil")
174171
}
175172

176173
dvBuilder := kvbuilder.NewDV(sup.DataVolume())
@@ -180,7 +177,7 @@ func (s DiskService) StartImmediate(
180177
dvBuilder.SetImmediate()
181178
dv := dvBuilder.GetResource()
182179

183-
err = s.client.Create(ctx, dv)
180+
err := s.client.Create(ctx, dv)
184181
if err != nil && !k8serrors.IsAlreadyExists(err) {
185182
return err
186183
}
@@ -455,7 +452,7 @@ func getAccessModeMax(modes []corev1.PersistentVolumeAccessMode) corev1.Persiste
455452
return m
456453
}
457454

458-
func (s DiskService) parseVolumeMode(sc *storev1.StorageClass) (corev1.PersistentVolumeMode, bool) {
455+
func (s DiskService) parseVolumeMode(sc *storagev1.StorageClass) (corev1.PersistentVolumeMode, bool) {
459456
if sc == nil {
460457
return "", false
461458
}
@@ -469,7 +466,7 @@ func (s DiskService) parseVolumeMode(sc *storev1.StorageClass) (corev1.Persisten
469466
}
470467
}
471468

472-
func (s DiskService) parseAccessMode(sc *storev1.StorageClass) (corev1.PersistentVolumeAccessMode, bool) {
469+
func (s DiskService) parseAccessMode(sc *storagev1.StorageClass) (corev1.PersistentVolumeAccessMode, bool) {
473470
if sc == nil {
474471
return "", false
475472
}
@@ -483,11 +480,11 @@ func (s DiskService) parseAccessMode(sc *storev1.StorageClass) (corev1.Persisten
483480
}
484481
}
485482

486-
func (s DiskService) isImmediateBindingMode(sc *storev1.StorageClass) bool {
483+
func (s DiskService) isImmediateBindingMode(sc *storagev1.StorageClass) bool {
487484
if sc == nil {
488485
return false
489486
}
490-
return sc.GetAnnotations()[annotations.AnnVirtualDiskBindingMode] == string(storev1.VolumeBindingImmediate)
487+
return sc.GetAnnotations()[annotations.AnnVirtualDiskBindingMode] == string(storagev1.VolumeBindingImmediate)
491488
}
492489

493490
func (s DiskService) parseStorageCapabilities(status cdiv1.StorageProfileStatus) StorageCapabilities {
@@ -521,6 +518,10 @@ func (s DiskService) parseStorageCapabilities(status cdiv1.StorageProfileStatus)
521518
return storageCapabilities[len(storageCapabilities)-1]
522519
}
523520

521+
func (s DiskService) GetStorageClass(ctx context.Context, scName string) (*storagev1.StorageClass, error) {
522+
return object.FetchObject(ctx, types.NamespacedName{Name: scName}, s.client, &storagev1.StorageClass{})
523+
}
524+
524525
func (s DiskService) GetDataVolume(ctx context.Context, sup *supplements.Generator) (*cdiv1.DataVolume, error) {
525526
return object.FetchObject(ctx, sup.DataVolume(), s.client, &cdiv1.DataVolume{})
526527
}
@@ -600,59 +601,6 @@ func (s DiskService) CheckImportProcess(ctx context.Context, dv *cdiv1.DataVolum
600601
return nil
601602
}
602603

603-
func (s DiskService) GetStorageClass(ctx context.Context, storageClassName *string) (*storev1.StorageClass, error) {
604-
if storageClassName == nil || *storageClassName == "" {
605-
return s.GetDefaultStorageClass(ctx)
606-
}
607-
return s.getStorageClass(ctx, *storageClassName)
608-
}
609-
610-
func (s DiskService) GetDefaultStorageClass(ctx context.Context) (*storev1.StorageClass, error) {
611-
var scs storev1.StorageClassList
612-
err := s.client.List(ctx, &scs, &client.ListOptions{})
613-
if err != nil {
614-
return nil, err
615-
}
616-
617-
var defaultClasses []*storev1.StorageClass
618-
for idx := range scs.Items {
619-
if scs.Items[idx].Annotations[annotations.AnnDefaultStorageClass] == "true" {
620-
defaultClasses = append(defaultClasses, &scs.Items[idx])
621-
}
622-
}
623-
624-
if len(defaultClasses) == 0 {
625-
return nil, ErrDefaultStorageClassNotFound
626-
}
627-
628-
// Primary sort by creation timestamp, newest first
629-
// Secondary sort by class name, ascending order
630-
sort.Slice(defaultClasses, func(i, j int) bool {
631-
if defaultClasses[i].CreationTimestamp.UnixNano() == defaultClasses[j].CreationTimestamp.UnixNano() {
632-
return defaultClasses[i].Name < defaultClasses[j].Name
633-
}
634-
return defaultClasses[i].CreationTimestamp.UnixNano() > defaultClasses[j].CreationTimestamp.UnixNano()
635-
})
636-
637-
return defaultClasses[0], nil
638-
}
639-
640-
func (s DiskService) getStorageClass(ctx context.Context, storageClassName string) (*storev1.StorageClass, error) {
641-
var sc storev1.StorageClass
642-
err := s.client.Get(ctx, types.NamespacedName{
643-
Name: storageClassName,
644-
}, &sc, &client.GetOptions{})
645-
if err != nil {
646-
if k8serrors.IsNotFound(err) {
647-
return nil, ErrStorageClassNotFound
648-
}
649-
650-
return nil, err
651-
}
652-
653-
return &sc, nil
654-
}
655-
656604
var ErrInsufficientPVCSize = errors.New("the specified pvc size is insufficient")
657605

658606
func GetValidatedPVCSize(pvcSize *resource.Quantity, requiredSize resource.Quantity) (resource.Quantity, error) {

images/virtualization-artifact/pkg/controller/service/mock.go

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ type Sources interface {
4141
type DiskService interface {
4242
Resize(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error
4343
GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error)
44-
GetStorageClass(ctx context.Context, storageClassName *string) (*storagev1.StorageClass, error)
4544
}
4645

4746
type StorageClassService interface {

0 commit comments

Comments
 (0)