Skip to content

Commit 635368f

Browse files
authored
Merge pull request kubernetes-sigs#3798 from skogta/topic/skogta/pvcBluePrint
Update PVC annotation with backing disk type for blueprint PVCs.
2 parents 85b220e + 0371f7c commit 635368f

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

pkg/syncer/cnsoperator/controller/cnsregistervolume/cnsregistervolume_controller.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ func (r *ReconcileCnsRegisterVolume) Reconcile(ctx context.Context,
669669
return reconcile.Result{RequeueAfter: timeout}, nil
670670
}
671671

672+
IsPVCCreatedByCNSRegisterVolumeReconciler := false
673+
672674
if pvc != nil {
673675
if pvc.Status.Phase == v1.ClaimBound && pvc.Spec.VolumeName != pvName {
674676
// This is handle cases where PVC with this name already exists and
@@ -730,6 +732,7 @@ func (r *ReconcileCnsRegisterVolume) Reconcile(ctx context.Context,
730732
return reconcile.Result{RequeueAfter: timeout}, nil
731733
} else {
732734
log.Infof("PVC: %s is created successfully", instance.Spec.PvcName)
735+
IsPVCCreatedByCNSRegisterVolumeReconciler = true
733736
}
734737
}
735738
// Watch for PVC to be bound.
@@ -839,6 +842,18 @@ func (r *ReconcileCnsRegisterVolume) Reconcile(ctx context.Context,
839842
return reconcile.Result{RequeueAfter: timeout}, nil
840843
}
841844

845+
if isSharedDiskEnabled && !IsPVCCreatedByCNSRegisterVolumeReconciler {
846+
// Ensure that the PVC has the correct backing disk annotation if PVC was already present on the cluster.
847+
if pvc != nil {
848+
pvc, err = setBackingDiskAnnotation(ctx, k8sclient, instance, pvc)
849+
if err != nil {
850+
msg := fmt.Sprintf("failed to update bakcing disk type on PVC. Error: %s", err)
851+
setInstanceError(ctx, r, instance, msg)
852+
return reconcile.Result{RequeueAfter: timeout}, nil
853+
}
854+
}
855+
}
856+
842857
// Update the instance to indicate the volume registration is successful.
843858
msg := fmt.Sprintf("Successfully registered the volume on namespace: %s", instance.Namespace)
844859
err = setInstanceSuccess(ctx, r, instance, instance.Spec.PvcName, pvc.UID, msg)

pkg/syncer/cnsoperator/controller/cnsregistervolume/cnsregistervolume_controller_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
k8sfake "k8s.io/client-go/kubernetes/fake"
4242
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
4343
restclient "k8s.io/client-go/rest"
44+
k8stesting "k8s.io/client-go/testing"
4445
"k8s.io/client-go/tools/record"
4546
"sigs.k8s.io/controller-runtime/pkg/client/fake"
4647
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -2266,3 +2267,108 @@ var _ = Describe("patchCnsRegisterVolumeStatus Tests", func() {
22662267
})
22672268
})
22682269
})
2270+
2271+
func TestSetBackingDiskAnnotationNoChangeNeeded(t *testing.T) {
2272+
ctx := context.Background()
2273+
2274+
pvc := &corev1.PersistentVolumeClaim{
2275+
ObjectMeta: metav1.ObjectMeta{
2276+
Name: "test-pvc",
2277+
Namespace: "default",
2278+
Annotations: map[string]string{
2279+
common.AnnKeyBackingDiskType: "backing-disk-type-1",
2280+
},
2281+
},
2282+
}
2283+
2284+
instance := &cnsregistervolumev1alpha1.CnsRegisterVolume{
2285+
Spec: cnsregistervolumev1alpha1.CnsRegisterVolumeSpec{
2286+
BackingType: "backing-disk-type-1",
2287+
},
2288+
}
2289+
2290+
client := k8sfake.NewSimpleClientset(pvc)
2291+
2292+
out, err := setBackingDiskAnnotation(ctx, client, instance, pvc)
2293+
2294+
assert.NoError(t, err)
2295+
assert.Equal(t, "backing-disk-type-1", out.Annotations[common.AnnKeyBackingDiskType])
2296+
2297+
// No patch should happen
2298+
actions := client.Actions()
2299+
assert.Len(t, actions, 0)
2300+
}
2301+
2302+
func TestSetBackingDiskAnnotationUpdateRequired(t *testing.T) {
2303+
ctx := context.Background()
2304+
2305+
pvc := &corev1.PersistentVolumeClaim{
2306+
ObjectMeta: metav1.ObjectMeta{
2307+
Name: "test-pvc",
2308+
Namespace: "default",
2309+
Annotations: map[string]string{common.AnnKeyBackingDiskType: "backing-disk-type-1"},
2310+
},
2311+
}
2312+
2313+
instance := &cnsregistervolumev1alpha1.CnsRegisterVolume{
2314+
Spec: cnsregistervolumev1alpha1.CnsRegisterVolumeSpec{
2315+
BackingType: "backing-disk-type-2",
2316+
},
2317+
}
2318+
2319+
client := k8sfake.NewSimpleClientset(pvc)
2320+
2321+
out, err := setBackingDiskAnnotation(ctx, client, instance, pvc)
2322+
assert.NoError(t, err)
2323+
assert.NotNil(t, out)
2324+
2325+
actions := client.Actions()
2326+
assert.Len(t, actions, 1)
2327+
2328+
patchAction, ok := actions[0].(k8stesting.PatchAction)
2329+
assert.True(t, ok, "expected PatchAction")
2330+
2331+
assert.Equal(t, "persistentvolumeclaims", patchAction.GetResource().Resource)
2332+
assert.Equal(t, "test-pvc", patchAction.GetName())
2333+
2334+
var patch map[string]map[string]map[string]string
2335+
err = json.Unmarshal(patchAction.GetPatch(), &patch)
2336+
assert.NoError(t, err)
2337+
2338+
assert.Equal(t, "backing-disk-type-2", patch["metadata"]["annotations"][common.AnnKeyBackingDiskType])
2339+
}
2340+
2341+
func TestSetBackingDiskAnnotationNoAnnotationsInitially(t *testing.T) {
2342+
ctx := context.Background()
2343+
2344+
pvc := &corev1.PersistentVolumeClaim{
2345+
ObjectMeta: metav1.ObjectMeta{
2346+
Name: "test-pvc",
2347+
Namespace: "default",
2348+
},
2349+
}
2350+
2351+
instance := &cnsregistervolumev1alpha1.CnsRegisterVolume{
2352+
Spec: cnsregistervolumev1alpha1.CnsRegisterVolumeSpec{
2353+
BackingType: "backing-disk-type-1",
2354+
},
2355+
}
2356+
2357+
client := k8sfake.NewSimpleClientset(pvc)
2358+
2359+
out, err := setBackingDiskAnnotation(ctx, client, instance, pvc)
2360+
assert.NoError(t, err)
2361+
assert.NotNil(t, out)
2362+
2363+
actions := client.Actions()
2364+
assert.Len(t, actions, 1)
2365+
2366+
patchAction, ok := actions[0].(k8stesting.PatchAction)
2367+
assert.True(t, ok)
2368+
2369+
var patch map[string]map[string]map[string]string
2370+
err = json.Unmarshal(patchAction.GetPatch(), &patch)
2371+
assert.NoError(t, err)
2372+
2373+
assert.Equal(t, "backing-disk-type-1", patch["metadata"]["annotations"][common.AnnKeyBackingDiskType])
2374+
}

pkg/syncer/cnsoperator/controller/cnsregistervolume/util.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"k8s.io/apimachinery/pkg/api/resource"
3232
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3333
"k8s.io/apimachinery/pkg/fields"
34+
"k8s.io/apimachinery/pkg/types"
3435
clientset "k8s.io/client-go/kubernetes"
3536
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
3637
cnsregistervolumev1alpha1 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/cnsregistervolume/v1alpha1"
@@ -391,3 +392,71 @@ func isPVCBound(ctx context.Context, client clientset.Interface, claim *v1.Persi
391392
return false, fmt.Errorf("persistentVolumeClaim %s in namespace %s not in phase %s within %d seconds",
392393
pvcName, ns, v1.ClaimBound, timeoutSeconds)
393394
}
395+
396+
// setBackingDiskAnnotation checks if the backing disk annotation on the PVC matches
397+
// the backing disk type mentioned on CnsRegisterVolume instance.
398+
func setBackingDiskAnnotation(ctx context.Context, k8sClient clientset.Interface,
399+
instance *cnsregistervolumev1alpha1.CnsRegisterVolume,
400+
pvc *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) {
401+
log := logger.GetLogger(ctx)
402+
log.Infof("Checking BackingType for PVC %s.", pvc.Name)
403+
404+
if instance.Spec.BackingType == "" {
405+
log.Infof("BackingType on instance %s is empty.", instance.Name)
406+
return pvc, nil
407+
}
408+
409+
if pvc.Annotations == nil {
410+
pvc.Annotations = make(map[string]string)
411+
}
412+
413+
backingDiskType, backingDiskAnnExists := pvc.Annotations[common.AnnKeyBackingDiskType]
414+
if backingDiskAnnExists {
415+
if backingDiskType == instance.Spec.BackingType {
416+
log.Infof("BackingType for PVC %s is up to date. Skip updating.", pvc.Name)
417+
return pvc, nil
418+
}
419+
}
420+
421+
log.Infof("Updating BackingType for PVC %s to %s",
422+
pvc.Name, instance.Spec.BackingType)
423+
424+
currentPvcAnnotations := pvc.Annotations
425+
426+
patchAnnotations := make(map[string]interface{})
427+
for k, v := range currentPvcAnnotations {
428+
patchAnnotations[k] = v
429+
}
430+
431+
backingDiskTypeOnSpec := instance.Spec.BackingType
432+
patchAnnotations[common.AnnKeyBackingDiskType] = backingDiskTypeOnSpec
433+
434+
// Build patch structure
435+
patch := map[string]interface{}{
436+
"metadata": map[string]interface{}{
437+
"annotations": patchAnnotations,
438+
},
439+
}
440+
patchBytes, err := json.Marshal(patch)
441+
if err != nil {
442+
log.Errorf("failed to marshal with annotations for PVC %s. Err: %s", pvc.Name, err)
443+
return pvc, fmt.Errorf("failed to marshal patch: %v", err)
444+
}
445+
446+
log.Infof("Patching PVC %s with updated annotation", pvc.Name)
447+
448+
// Apply the patch
449+
updatedpvc, err := k8sClient.CoreV1().PersistentVolumeClaims(pvc.Namespace).Patch(
450+
ctx,
451+
pvc.Name,
452+
types.MergePatchType,
453+
patchBytes,
454+
metav1.PatchOptions{},
455+
)
456+
if err != nil {
457+
log.Errorf("failed to patch PVC %s with annotations. Err: %s", pvc.Name, err)
458+
return pvc, fmt.Errorf("failed to patch PVC %s: %v", pvc.Name, err)
459+
}
460+
461+
return updatedpvc, nil
462+
}

0 commit comments

Comments
 (0)