Skip to content

Commit 63e1575

Browse files
Add StorageProfile "Recognized" status condition
Explaining if the provisioner or the storage class parameters are not recognized, so ClaimPropertySets are not auto-filled and need to be specified by the user. Signed-off-by: Arnon Gilboa <[email protected]> Co-authored-by: Cursor <[email protected]>
1 parent c841de9 commit 63e1575

8 files changed

Lines changed: 224 additions & 1 deletion

File tree

pkg/apis/core/v1beta1/openapi_generated.go

Lines changed: 68 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controller/storageprofile-controller.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ const (
5252
counterLabelRWX = "rwx"
5353
counterLabelSmartClone = "smartclone"
5454
counterLabelDegraded = "degraded"
55+
56+
recognizedProvisionerMessage = "Provisioner is recognized"
57+
unrecognizedProvisionerMessage = "Provisioner is not recognized"
58+
unrecognizedStorageClassParametersMessage = "Storage class parameters are not recognized"
5559
)
5660

5761
// StorageProfileReconciler members
@@ -125,6 +129,7 @@ func (r *StorageProfileReconciler) reconcileStorageProfile(sc *storagev1.Storage
125129
}
126130

127131
storageProfile.Status.ClaimPropertySets = claimPropertySets
132+
r.reconcileConditions(context.TODO(), sc, storageProfile)
128133

129134
util.SetRecommendedLabels(storageProfile, r.installerLabels, "cdi-controller")
130135
if err := r.updateStorageProfile(prevStorageProfile, storageProfile, log); err != nil {
@@ -198,6 +203,32 @@ func (r *StorageProfileReconciler) getStorageProfile(sc *storagev1.StorageClass)
198203
return storageProfile, prevStorageProfile, nil
199204
}
200205

206+
func (r *StorageProfileReconciler) reconcileConditions(ctx context.Context, sc *storagev1.StorageClass, sp *cdiv1.StorageProfile) {
207+
cond := findStorageProfileConditionByType(sp, cdiv1.StorageProfileRecognized)
208+
if cond == nil {
209+
sp.Status.Conditions = append(sp.Status.Conditions, cdiv1.StorageProfileCondition{Type: cdiv1.StorageProfileRecognized})
210+
cond = &sp.Status.Conditions[len(sp.Status.Conditions)-1]
211+
}
212+
213+
switch reason := storagecapabilities.IsRecognized(sc); reason {
214+
case storagecapabilities.RecognizedProvisioner:
215+
updateConditionState(&cond.ConditionState, v1.ConditionTrue, recognizedProvisionerMessage, string(reason))
216+
case storagecapabilities.UnrecognizedProvisioner:
217+
updateConditionState(&cond.ConditionState, v1.ConditionFalse, unrecognizedProvisionerMessage, string(reason))
218+
case storagecapabilities.UnrecognizedStorageClassParameters:
219+
updateConditionState(&cond.ConditionState, v1.ConditionFalse, unrecognizedStorageClassParametersMessage, string(reason))
220+
}
221+
}
222+
223+
func findStorageProfileConditionByType(sp *cdiv1.StorageProfile, condType cdiv1.StorageProfileConditionType) *cdiv1.StorageProfileCondition {
224+
for i := range sp.Status.Conditions {
225+
if sp.Status.Conditions[i].Type == condType {
226+
return &sp.Status.Conditions[i]
227+
}
228+
}
229+
return nil
230+
}
231+
201232
func (r *StorageProfileReconciler) reconcilePropertySets(sc *storagev1.StorageClass) []cdiv1.ClaimPropertySet {
202233
claimPropertySets := []cdiv1.ClaimPropertySet{}
203234
capabilities, found := storagecapabilities.GetCapabilities(r.client, sc)

pkg/controller/storageprofile-controller_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,35 @@ var _ = Describe("Storage profile controller reconcile loop", func() {
651651
Entry("Without RWX, on SNO, not degraded", v1.ReadWriteOnce, true, false),
652652
)
653653

654+
DescribeTable("Should set Recognized condition", func(provisioner string, scParameters map[string]string, expectedStatus v1.ConditionStatus, expectedReason, expectedMessage string) {
655+
storageClass := CreateStorageClassWithProvisioner(storageClassName, nil, nil, provisioner)
656+
storageClass.Parameters = scParameters
657+
reconciler = createStorageProfileReconciler(storageClass)
658+
_, err := reconciler.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Name: storageClassName}})
659+
Expect(err).ToNot(HaveOccurred())
660+
661+
sp := &cdiv1.StorageProfile{}
662+
err = reconciler.client.Get(context.TODO(), types.NamespacedName{Name: storageClassName}, sp, &client.GetOptions{})
663+
Expect(err).ToNot(HaveOccurred())
664+
665+
Expect(sp.Status.Conditions).To(HaveLen(1))
666+
cond := sp.Status.Conditions[0]
667+
Expect(cond.Type).To(Equal(cdiv1.StorageProfileRecognized))
668+
Expect(cond.Status).To(Equal(expectedStatus))
669+
Expect(cond.Reason).To(Equal(expectedReason))
670+
Expect(cond.Message).To(Equal(expectedMessage))
671+
},
672+
Entry("recognized provisioner",
673+
cephProvisioner, nil,
674+
v1.ConditionTrue, string(storagecapabilities.RecognizedProvisioner), recognizedProvisionerMessage),
675+
Entry("unrecognized provisioner",
676+
"unknown-provisioner", nil,
677+
v1.ConditionFalse, string(storagecapabilities.UnrecognizedProvisioner), unrecognizedProvisionerMessage),
678+
Entry("recognized provisioner with unrecognized parameters",
679+
"infinibox-csi-driver", map[string]string{"storage_protocol": "unsupported"},
680+
v1.ConditionFalse, string(storagecapabilities.UnrecognizedStorageClassParameters), unrecognizedStorageClassParametersMessage),
681+
)
682+
654683
})
655684

656685
func createStorageProfileReconciler(objects ...runtime.Object) *StorageProfileReconciler {

pkg/operator/resources/crds_generated.go

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

pkg/storagecapabilities/storagecapabilities.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,27 @@ var UnsupportedProvisioners = map[string]struct{}{
259259
storagehelpers.NotSupportedProvisioner: {},
260260
}
261261

262+
// StorageClassRecognizeReason represents the reason for the storage class recognition condition
263+
type StorageClassRecognizeReason string
264+
265+
const (
266+
RecognizedProvisioner StorageClassRecognizeReason = "RecognizedProvisioner"
267+
UnrecognizedProvisioner StorageClassRecognizeReason = "UnrecognizedProvisioner"
268+
UnrecognizedStorageClassParameters StorageClassRecognizeReason = "UnrecognizedStorageClassParameters"
269+
)
270+
271+
// IsRecognized checks if the storage class provisioner and parameters are recognized so capabilities are available
272+
func IsRecognized(sc *storagev1.StorageClass) StorageClassRecognizeReason {
273+
provisionerKey := storageProvisionerKey(sc)
274+
if provisionerKey == "UNKNOWN" {
275+
return UnrecognizedStorageClassParameters
276+
}
277+
if _, found := CapabilitiesByProvisionerKey[provisionerKey]; found {
278+
return RecognizedProvisioner
279+
}
280+
return UnrecognizedProvisioner
281+
}
282+
262283
// GetCapabilities finds and returns a predefined StorageCapabilities for a given StorageClass
263284
func GetCapabilities(cl client.Client, sc *storagev1.StorageClass) ([]StorageCapabilities, bool) {
264285
provisionerKey := storageProvisionerKey(sc)

staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1/types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,24 @@ type StorageProfileStatus struct {
467467
DataImportCronSourceFormat *DataImportCronSourceFormat `json:"dataImportCronSourceFormat,omitempty"`
468468
// SnapshotClass is optional specific VolumeSnapshotClass for CloneStrategySnapshot. If not set, a VolumeSnapshotClass is chosen according to the provisioner.
469469
SnapshotClass *string `json:"snapshotClass,omitempty"`
470+
// Conditions contains the current conditions observed for the StorageProfile
471+
Conditions []StorageProfileCondition `json:"conditions,omitempty" optional:"true"`
470472
}
471473

474+
// StorageProfileCondition represents the state of a storage profile condition
475+
type StorageProfileCondition struct {
476+
Type StorageProfileConditionType `json:"type" description:"type of condition ie. Recognized"`
477+
ConditionState `json:",inline"`
478+
}
479+
480+
// StorageProfileConditionType is the string representation of known condition types
481+
type StorageProfileConditionType string
482+
483+
const (
484+
// StorageProfileRecognized is the condition that indicates if the storage class provisioner and parameters are recognized by CDI
485+
StorageProfileRecognized StorageProfileConditionType = "Recognized"
486+
)
487+
472488
// ClaimPropertySet is a set of properties applicable to PVC
473489
type ClaimPropertySet struct {
474490
// AccessModes contains the desired access modes the volume should have.

staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1/types_swagger_generated.go

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

staging/src/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1/zz_generated.deepcopy.go

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

0 commit comments

Comments
 (0)