Skip to content

Commit a0840f3

Browse files
author
Roman Sysoev
committed
fix(vi,vd): fix default storage class usage
- handle default storage class from the module config - fix `StorageClassReady` condition Signed-off-by: Roman Sysoev <roman.sysoev@flant.com>
1 parent 0c2a6bb commit a0840f3

16 files changed

Lines changed: 523 additions & 101 deletions

File tree

api/core/v1alpha2/events.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ const (
8282
// ReasonVDResizingNotAvailable is event reason that VD Resizing is not available.
8383
ReasonVDResizingNotAvailable = "VirtualDiskResizingNotAvailable"
8484

85+
// ReasonVIStorageClassNotFound is event reason that VIStorageClass not found.
86+
ReasonVIStorageClassNotFound = "VirtualImageStorageClassNotFound"
87+
8588
// ReasonDataSourceSyncStarted is event reason that DataSource sync is started.
8689
ReasonDataSourceSyncStarted = "DataSourceImportStarted"
8790
// ReasonDataSourceSyncInProgress is event reason that DataSource sync is in progress.

api/core/v1alpha2/vicondition/condition.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ const (
7979
ProvisioningNotStarted ReadyReason = "ProvisioningNotStarted"
8080
// ProvisioningFailed indicates that the provisioning process has failed.
8181
ProvisioningFailed ReadyReason = "ProvisioningFailed"
82-
// StorageClassNotReady indicates that the provisioning process pending because `StorageClass` not ready.
83-
StorageClassNotReady ReadyReason = "StorageClassNotReady"
8482
// Ready indicates that the import process is complete and the `VirtualImage` is ready for use.
8583
Ready ReadyReason = "Ready"
8684
// QuotaExceeded indicates that the VirtualImage is reached project quotas and can not be provisioned.
@@ -93,6 +91,8 @@ const (
9391

9492
// StorageClassReady indicates that the chosen StorageClass exists.
9593
StorageClassReady StorageClassReadyReason = "StorageClassReady"
94+
// StorageClassNotReady indicates that the provisioning process pending because `StorageClass` not ready.
95+
StorageClassNotReady ReadyReason = "StorageClassNotReady"
9696
// StorageClassNotFound indicates that the chosen StorageClass not found.
9797
StorageClassNotFound StorageClassReadyReason = "StorageClassNotFound"
9898
// DVCRTypeUsed indicates that the DVCR provisioning chosen.

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,25 @@ limitations under the License.
1717
package service
1818

1919
import (
20+
"context"
2021
"slices"
2122

23+
corev1 "k8s.io/api/core/v1"
2224
storev1 "k8s.io/api/storage/v1"
2325

2426
"github.com/deckhouse/virtualization-controller/pkg/config"
27+
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
2528
)
2629

2730
type VirtualImageStorageClassService struct {
2831
storageClassSettings config.VirtualImageStorageClassSettings
32+
scGetter StorageClassGetter
2933
}
3034

31-
func NewVirtualImageStorageClassService(settings config.VirtualImageStorageClassSettings) *VirtualImageStorageClassService {
35+
func NewVirtualImageStorageClassService(settings config.VirtualImageStorageClassSettings, scGetter StorageClassGetter) *VirtualImageStorageClassService {
3236
return &VirtualImageStorageClassService{
3337
storageClassSettings: settings,
38+
scGetter: scGetter,
3439
}
3540
}
3641

@@ -47,7 +52,7 @@ func NewVirtualImageStorageClassService(settings config.VirtualImageStorageClass
4752
// Errors:
4853
// 1. Return error if no storage class is specified.
4954
// 2. Return error if specified non-empty class is not allowed.
50-
func (svc *VirtualImageStorageClassService) GetStorageClass(storageClassFromSpec *string, clusterDefaultStorageClass *storev1.StorageClass) (*string, error) {
55+
func (svc *VirtualImageStorageClassService) GetValidatedStorageClass(storageClassFromSpec *string, clusterDefaultStorageClass *storev1.StorageClass) (*string, error) {
5156
if svc.storageClassSettings.DefaultStorageClassName == "" && len(svc.storageClassSettings.AllowedStorageClassNames) == 0 {
5257
if svc.storageClassSettings.StorageClassName == "" {
5358
return storageClassFromSpec, nil
@@ -86,3 +91,35 @@ func (svc *VirtualImageStorageClassService) GetStorageClass(storageClassFromSpec
8691

8792
return nil, ErrStorageClassNotFound
8893
}
94+
95+
func (svc *VirtualImageStorageClassService) IsStorageClassAllowed(scName string) bool {
96+
if svc.storageClassSettings.DefaultStorageClassName == "" && len(svc.storageClassSettings.AllowedStorageClassNames) == 0 {
97+
return true
98+
}
99+
100+
if slices.Contains(svc.storageClassSettings.AllowedStorageClassNames, scName) {
101+
return true
102+
}
103+
104+
if svc.storageClassSettings.DefaultStorageClassName != "" && svc.storageClassSettings.DefaultStorageClassName == scName {
105+
return true
106+
}
107+
108+
return false
109+
}
110+
111+
func (svc *VirtualImageStorageClassService) GetModuleStorageClass(ctx context.Context) (*storev1.StorageClass, error) {
112+
return svc.GetStorageClass(ctx, svc.storageClassSettings.DefaultStorageClassName)
113+
}
114+
115+
func (svc *VirtualImageStorageClassService) GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) {
116+
return svc.scGetter.GetPersistentVolumeClaim(ctx, sup)
117+
}
118+
119+
func (svc *VirtualImageStorageClassService) GetStorageClass(ctx context.Context, scName string) (*storev1.StorageClass, error) {
120+
return svc.scGetter.GetStorageClass(ctx, &scName)
121+
}
122+
123+
func (svc *VirtualImageStorageClassService) GetDefaultStorageClass(ctx context.Context) (*storev1.StorageClass, error) {
124+
return svc.scGetter.GetDefaultStorageClass(ctx)
125+
}

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

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ var _ = Describe("VirtualImageStorageClassService", func() {
4040
Context("when settings are empty", func() {
4141
It("returns the storageClassFromSpec", func() {
4242
storageClassSettings = config.VirtualImageStorageClassSettings{}
43-
service = NewVirtualImageStorageClassService(storageClassSettings)
43+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
4444
sc := ptr.To("requested-storage-class")
45-
storageClass, err := service.GetStorageClass(sc, clusterDefaultStorageClass)
45+
storageClass, err := service.GetValidatedStorageClass(sc, clusterDefaultStorageClass)
4646

4747
Expect(err).To(BeNil())
4848
Expect(storageClass).To(Equal(sc))
@@ -52,9 +52,9 @@ var _ = Describe("VirtualImageStorageClassService", func() {
5252
Context("when settings are empty and storageClassFromSpec is empty", func() {
5353
It("returns the storageClassFromSpec", func() {
5454
storageClassSettings = config.VirtualImageStorageClassSettings{}
55-
service = NewVirtualImageStorageClassService(storageClassSettings)
55+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
5656

57-
storageClass, err := service.GetStorageClass(nil, clusterDefaultStorageClass)
57+
storageClass, err := service.GetValidatedStorageClass(nil, clusterDefaultStorageClass)
5858

5959
Expect(err).To(BeNil())
6060
Expect(storageClass).To(BeNil())
@@ -64,9 +64,9 @@ var _ = Describe("VirtualImageStorageClassService", func() {
6464
Context("when settings and clusterDefaultStorageClass are empty", func() {
6565
It("returns the storageClassFromSpec", func() {
6666
storageClassSettings = config.VirtualImageStorageClassSettings{}
67-
service = NewVirtualImageStorageClassService(storageClassSettings)
67+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
6868
sc := ptr.To("requested-storage-class")
69-
storageClass, err := service.GetStorageClass(sc, nil)
69+
storageClass, err := service.GetValidatedStorageClass(sc, nil)
7070

7171
Expect(err).To(BeNil())
7272
Expect(storageClass).To(Equal(sc))
@@ -78,24 +78,24 @@ var _ = Describe("VirtualImageStorageClassService", func() {
7878
storageClassSettings = config.VirtualImageStorageClassSettings{
7979
StorageClassName: "storage-class-name",
8080
}
81-
service = NewVirtualImageStorageClassService(storageClassSettings)
81+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
8282
})
8383

8484
It("return the StorageClassName if storageClassFromSpec is empty", func() {
85-
storageClass, err := service.GetStorageClass(nil, nil)
85+
storageClass, err := service.GetValidatedStorageClass(nil, nil)
8686
Expect(err).To(BeNil())
8787
Expect(storageClass).To(Equal(&storageClassSettings.StorageClassName))
8888
})
8989

9090
It("return the StorageClassName if storageClassFromSpec equal StorageClassName", func() {
91-
storageClass, err := service.GetStorageClass(&storageClassSettings.StorageClassName, nil)
91+
storageClass, err := service.GetValidatedStorageClass(&storageClassSettings.StorageClassName, nil)
9292
Expect(err).To(BeNil())
9393
Expect(storageClass).To(Equal(&storageClassSettings.StorageClassName))
9494
})
9595

9696
It("return the err if storageClassFromSpec not equal StorageClassName", func() {
9797
sc := ptr.To("requested-storage-class")
98-
_, err := service.GetStorageClass(sc, nil)
98+
_, err := service.GetValidatedStorageClass(sc, nil)
9999
Expect(err).To(Equal(ErrStorageClassNotAllowed))
100100
})
101101
})
@@ -106,25 +106,25 @@ var _ = Describe("VirtualImageStorageClassService", func() {
106106
AllowedStorageClassNames: []string{"allowed-storage-class"},
107107
DefaultStorageClassName: "",
108108
}
109-
service = NewVirtualImageStorageClassService(storageClassSettings)
109+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
110110
})
111111

112112
It("returns the requested storage class if it's in the allowed list", func() {
113113
sc := ptr.To("allowed-storage-class")
114-
storageClass, err := service.GetStorageClass(sc, clusterDefaultStorageClass)
114+
storageClass, err := service.GetValidatedStorageClass(sc, clusterDefaultStorageClass)
115115

116116
Expect(err).To(BeNil())
117117
Expect(storageClass).To(Equal(sc))
118118
})
119119

120120
It("returns an error if the requested storage class is not in the allowed list", func() {
121-
_, err := service.GetStorageClass(ptr.To("not-allowed-storage-class"), clusterDefaultStorageClass)
121+
_, err := service.GetValidatedStorageClass(ptr.To("not-allowed-storage-class"), clusterDefaultStorageClass)
122122

123123
Expect(err).To(Equal(ErrStorageClassNotAllowed))
124124
})
125125

126126
It("returns an error if storageClassFromSpec is empty", func() {
127-
_, err := service.GetStorageClass(nil, clusterDefaultStorageClass)
127+
_, err := service.GetValidatedStorageClass(nil, clusterDefaultStorageClass)
128128

129129
Expect(err).To(Equal(ErrStorageClassNotAllowed))
130130
})
@@ -136,26 +136,26 @@ var _ = Describe("VirtualImageStorageClassService", func() {
136136
AllowedStorageClassNames: []string{},
137137
DefaultStorageClassName: "default-storage-class",
138138
}
139-
service = NewVirtualImageStorageClassService(storageClassSettings)
139+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
140140
})
141141

142142
It("returns the default storage class if storageClassFromSpec is empty", func() {
143-
storageClass, err := service.GetStorageClass(nil, clusterDefaultStorageClass)
143+
storageClass, err := service.GetValidatedStorageClass(nil, clusterDefaultStorageClass)
144144

145145
Expect(err).To(BeNil())
146146
Expect(storageClass).To(Equal(ptr.To("default-storage-class")))
147147
})
148148

149149
It("returns the requested storage class if it matches the default storage class", func() {
150150
sc := ptr.To("default-storage-class")
151-
storageClass, err := service.GetStorageClass(sc, clusterDefaultStorageClass)
151+
storageClass, err := service.GetValidatedStorageClass(sc, clusterDefaultStorageClass)
152152

153153
Expect(err).To(BeNil())
154154
Expect(storageClass).To(Equal(sc))
155155
})
156156

157157
It("returns an error if the requested storage class does not match the default", func() {
158-
_, err := service.GetStorageClass(ptr.To("different-storage-class"), clusterDefaultStorageClass)
158+
_, err := service.GetValidatedStorageClass(ptr.To("different-storage-class"), clusterDefaultStorageClass)
159159

160160
Expect(err).To(Equal(ErrStorageClassNotAllowed))
161161
})
@@ -167,26 +167,26 @@ var _ = Describe("VirtualImageStorageClassService", func() {
167167
AllowedStorageClassNames: []string{"allowed-storage-class"},
168168
DefaultStorageClassName: "default-storage-class",
169169
}
170-
service = NewVirtualImageStorageClassService(storageClassSettings)
170+
service = NewVirtualImageStorageClassService(storageClassSettings, nil)
171171
})
172172

173173
It("returns the default storage class if storageClassFromSpec is empty", func() {
174-
storageClass, err := service.GetStorageClass(nil, clusterDefaultStorageClass)
174+
storageClass, err := service.GetValidatedStorageClass(nil, clusterDefaultStorageClass)
175175

176176
Expect(err).To(BeNil())
177177
Expect(storageClass).To(Equal(ptr.To("default-storage-class")))
178178
})
179179

180180
It("returns the requested storage class if it's in the allowed list", func() {
181181
sc := ptr.To("allowed-storage-class")
182-
storageClass, err := service.GetStorageClass(sc, clusterDefaultStorageClass)
182+
storageClass, err := service.GetValidatedStorageClass(sc, clusterDefaultStorageClass)
183183

184184
Expect(err).To(BeNil())
185185
Expect(storageClass).To(Equal(sc))
186186
})
187187

188188
It("returns an error if the requested storage class is not in the allowed list", func() {
189-
_, err := service.GetStorageClass(ptr.To("not-allowed-storage-class"), clusterDefaultStorageClass)
189+
_, err := service.GetValidatedStorageClass(ptr.To("not-allowed-storage-class"), clusterDefaultStorageClass)
190190

191191
Expect(err).To(Equal(ErrStorageClassNotAllowed))
192192
})

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

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

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223

2324
corev1 "k8s.io/api/core/v1"
@@ -27,6 +28,7 @@ import (
2728

2829
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
2930
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
31+
"github.com/deckhouse/virtualization-controller/pkg/controller/service"
3032
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
3133
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
3234
"github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition"
@@ -76,7 +78,7 @@ func (h StorageClassReadyHandler) Handle(ctx context.Context, vd *virtv2.Virtual
7678

7779
// 3. Try to use default storage class from the module settings.
7880
moduleStorageClass, err := h.svc.GetModuleStorageClass(ctx)
79-
if err != nil {
81+
if err != nil && !errors.Is(err, service.ErrDefaultStorageClassNotFound) {
8082
return reconcile.Result{}, fmt.Errorf("get module storage class: %w", err)
8183
}
8284

@@ -87,7 +89,7 @@ func (h StorageClassReadyHandler) Handle(ctx context.Context, vd *virtv2.Virtual
8789

8890
// 4. Try to use default storage class from the cluster.
8991
defaultStorageClass, err := h.svc.GetDefaultStorageClass(ctx)
90-
if err != nil {
92+
if err != nil && !errors.Is(err, service.ErrDefaultStorageClassNotFound) {
9193
return reconcile.Result{}, fmt.Errorf("get default storage class: %w", err)
9294
}
9395

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ import (
2020
"context"
2121

2222
corev1 "k8s.io/api/core/v1"
23-
storev1 "k8s.io/api/storage/v1"
23+
storagev1 "k8s.io/api/storage/v1"
2424

2525
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
2626
"github.com/deckhouse/virtualization-controller/pkg/controller/vi/internal/source"
2727
virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2"
2828
)
2929

30-
//go:generate moq -rm -out mock.go . DiskService Sources
30+
//go:generate moq -rm -out mock.go . DiskService Sources StorageClassService
3131

3232
type Sources interface {
3333
Changed(ctx context.Context, vi *virtv2.VirtualImage) bool
@@ -36,6 +36,14 @@ type Sources interface {
3636
}
3737

3838
type DiskService interface {
39-
GetStorageClass(ctx context.Context, storageClassName *string) (*storev1.StorageClass, error)
39+
GetStorageClass(ctx context.Context, storageClassName *string) (*storagev1.StorageClass, error)
40+
GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error)
41+
}
42+
43+
type StorageClassService interface {
44+
IsStorageClassAllowed(sc string) bool
45+
GetModuleStorageClass(ctx context.Context) (*storagev1.StorageClass, error)
46+
GetDefaultStorageClass(ctx context.Context) (*storagev1.StorageClass, error)
47+
GetStorageClass(ctx context.Context, sc string) (*storagev1.StorageClass, error)
4048
GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error)
4149
}

0 commit comments

Comments
 (0)