@@ -1173,10 +1173,12 @@ func validateAndFixPVVolumeMode(ctx context.Context, k8sclient clientset.Interfa
11731173func setInstanceError (ctx context.Context , r * ReconcileCnsRegisterVolume ,
11741174 instance * cnsregistervolumev1alpha1.CnsRegisterVolume , errMsg string ) {
11751175 log := logger .GetLogger (ctx )
1176+ origInstance := instance .DeepCopy ()
1177+ instance .Status .Registered = false
11761178 instance .Status .Error = errMsg
1177- err := k8s . UpdateStatus (ctx , r .client , instance )
1179+ err := patchCnsRegisterVolumeStatus (ctx , r .client , origInstance , instance )
11781180 if err != nil {
1179- log .Errorf ("updateCnsRegisterVolume failed. err: %v" , err )
1181+ log .Errorf ("patchCnsRegisterVolumeStatus failed. err: %v" , err )
11801182 return
11811183 }
11821184 recordEvent (ctx , r , instance , v1 .EventTypeWarning , errMsg )
@@ -1205,11 +1207,12 @@ func setInstanceSuccess(ctx context.Context, r *ReconcileCnsRegisterVolume,
12051207 return err
12061208 }
12071209 // Now update the status subresource with the fresh object
1210+ origInstance := instance .DeepCopy ()
12081211 instance .Status .Registered = true
12091212 instance .Status .Error = ""
1210- err = k8s . UpdateStatus (ctx , r .client , instance )
1213+ err = patchCnsRegisterVolumeStatus (ctx , r .client , origInstance , instance )
12111214 if err != nil {
1212- log .Errorf ("updateCnsRegisterVolume status failed. err: %v" , err )
1215+ log .Errorf ("patchCnsRegisterVolumeStatus failed. err: %v" , err )
12131216 return err
12141217 }
12151218 recordEvent (ctx , r , instance , v1 .EventTypeNormal , msg )
@@ -1273,3 +1276,59 @@ func updateCnsRegisterVolume(ctx context.Context, client client.Client,
12731276 }
12741277 return err
12751278}
1279+
1280+ // patchCnsRegisterVolumeStatus patches status field of CnsRegisterVolume instance in K8S.
1281+ // For status subresources with required fields, we need to ensure those fields are always
1282+ // included in the patch, even if they haven't changed. This is because Kubernetes validates
1283+ // the patch against the CRD schema which marks 'registered' as required.
1284+ func patchCnsRegisterVolumeStatus (ctx context.Context , cnsOperatorClient client.Client ,
1285+ oldObj * cnsregistervolumev1alpha1.CnsRegisterVolume ,
1286+ newObj * cnsregistervolumev1alpha1.CnsRegisterVolume ) error {
1287+ log := logger .GetLogger (ctx )
1288+
1289+ // For status patches with required fields, we use a simple JSON patch that always
1290+ // includes required status fields to satisfy CRD validation
1291+ var statusPatch map [string ]interface {}
1292+ if newObj .Status .Error != "" {
1293+ statusPatch = map [string ]interface {}{
1294+ "status" : map [string ]interface {}{
1295+ "registered" : newObj .Status .Registered ,
1296+ "error" : newObj .Status .Error ,
1297+ },
1298+ }
1299+ } else {
1300+ statusPatch = map [string ]interface {}{
1301+ "status" : map [string ]interface {}{
1302+ "registered" : newObj .Status .Registered ,
1303+ },
1304+ }
1305+ }
1306+
1307+ patchBytes , err := json .Marshal (statusPatch )
1308+ if err != nil {
1309+ log .Errorf ("failed to marshal status patch. err: %v" , err )
1310+ return err
1311+ }
1312+
1313+ rawPatch := client .RawPatch (apitypes .MergePatchType , patchBytes )
1314+
1315+ // Try to patch CnsRegisterVolume CR for 3 times
1316+ allowedRetries := 3
1317+ attempt := 0
1318+ for {
1319+ attempt ++
1320+ err := cnsOperatorClient .Status ().Patch (ctx , oldObj , rawPatch )
1321+ if err != nil && attempt >= allowedRetries {
1322+ log .Errorf ("failed to patch CnsRegisterVolume instance %q on namespace %q, Error: %+v" ,
1323+ oldObj .Name , oldObj .Namespace , err )
1324+ return err
1325+ } else if err == nil {
1326+ log .Debugf ("Successfully patched CnsRegisterVolume instance %q on namespace %q" ,
1327+ oldObj .Name , oldObj .Namespace )
1328+ return nil
1329+ }
1330+ log .Warnf ("attempt %d, failed to patch CnsRegisterVolume instance %q on namespace %q with error %+v, " +
1331+ "will retry..." , attempt , oldObj .Name , oldObj .Namespace , err )
1332+ time .Sleep (100 * time .Millisecond )
1333+ }
1334+ }
0 commit comments