@@ -22,20 +22,24 @@ import (
2222 "encoding/hex"
2323 "fmt"
2424 "path/filepath"
25+ "reflect"
2526 "strings"
2627 "time"
2728
2829 "github.com/go-logr/logr"
2930 "github.com/pkg/errors"
3031 corev1 "k8s.io/api/core/v1"
3132 "k8s.io/apimachinery/pkg/types"
33+ "k8s.io/client-go/util/retry"
3234 "sigs.k8s.io/controller-runtime/pkg/client"
3335
3436 "github.com/fluid-cloudnative/fluid/pkg/application/inject/fuse/poststart"
3537 "github.com/fluid-cloudnative/fluid/pkg/common"
3638 "github.com/fluid-cloudnative/fluid/pkg/ddc/base"
3739 "github.com/fluid-cloudnative/fluid/pkg/utils"
3840 "github.com/fluid-cloudnative/fluid/pkg/utils/kubeclient"
41+
42+ datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
3943)
4044
4145var (
@@ -321,20 +325,9 @@ func prepareFuseContainerPostStartScript(helper *helperData) error {
321325 // Fluid assumes pvc name is the same with runtime's name
322326 gen := poststart .NewDefaultPostStartScriptGenerator ()
323327 cmKey := gen .GetNamespacedConfigMapKey (types.NamespacedName {Namespace : datasetNamespace , Name : datasetName }, template .FuseMountInfo .FsType )
324- found , err := kubeclient .IsConfigMapExist (helper .client , cmKey .Name , cmKey .Namespace )
325- if err != nil {
326- return err
327- }
328328
329- if ! found {
330- cm := gen .BuildConfigMap (dataset , cmKey )
331- err = helper .client .Create (context .TODO (), cm )
332- if err != nil {
333- // If ConfigMap creation succeeds concurrently, continue to mutate
334- if otherErr := utils .IgnoreAlreadyExists (err ); otherErr != nil {
335- return err
336- }
337- }
329+ if err = ensurePostStartConfigMap (helper .client , gen , dataset , cmKey ); err != nil {
330+ return err
338331 }
339332
340333 template .FuseContainer .VolumeMounts = append (template .FuseContainer .VolumeMounts , gen .GetVolumeMount ())
@@ -347,6 +340,63 @@ func prepareFuseContainerPostStartScript(helper *helperData) error {
347340 return nil
348341}
349342
343+ // ensurePostStartConfigMap creates the ConfigMap if it does not exist, or updates it when the
344+ // script content has changed (detected via SHA256 annotation).
345+ func ensurePostStartConfigMap (c client.Client , gen poststart.ScriptGenerator , dataset * datav1alpha1.Dataset , cmKey types.NamespacedName ) error {
346+ existingCM , err := kubeclient .GetConfigmapByName (c , cmKey .Name , cmKey .Namespace )
347+ if err != nil {
348+ return err
349+ }
350+
351+ if existingCM == nil {
352+ cm := gen .BuildConfigMap (dataset , cmKey )
353+ if createErr := c .Create (context .TODO (), cm ); createErr != nil {
354+ // If ConfigMap creation succeeds concurrently, continue to mutate
355+ return utils .IgnoreAlreadyExists (createErr )
356+ }
357+ return nil
358+ }
359+
360+ // ConfigMap exists; update with retry on conflict to handle concurrent webhook mutations.
361+ return retry .RetryOnConflict (retry .DefaultBackoff , func () error {
362+ return updateConfigMapIfStale (c , gen , dataset , cmKey )
363+ })
364+ }
365+
366+ // updateConfigMapIfStale fetches the current ConfigMap from the cluster and updates it when the
367+ // SHA256 annotation does not match the latest script. It is designed to be called inside a
368+ // RetryOnConflict loop.
369+ func updateConfigMapIfStale (c client.Client , gen poststart.ScriptGenerator , dataset * datav1alpha1.Dataset , cmKey types.NamespacedName ) error {
370+ current , err := kubeclient .GetConfigmapByName (c , cmKey .Name , cmKey .Namespace )
371+ if err != nil {
372+ return err
373+ }
374+ if current == nil {
375+ // Deleted between Get calls; recreate
376+ return c .Create (context .TODO (), gen .BuildConfigMap (dataset , cmKey ))
377+ }
378+
379+ if isConfigMapUpToDate (current , gen .GetScriptSHA256 ()) {
380+ return nil
381+ }
382+
383+ latest := gen .RefreshConfigMapContents (dataset , cmKey , current .DeepCopy ())
384+ if reflect .DeepEqual (current , latest ) {
385+ return nil
386+ }
387+ return c .Update (context .TODO (), latest )
388+ }
389+
390+ // isConfigMapUpToDate returns true when the annotations already carry the expected SHA256,
391+ // meaning no update is needed.
392+ func isConfigMapUpToDate (cm * corev1.ConfigMap , expectedSHA256 string ) bool {
393+ if cm == nil || cm .Annotations == nil {
394+ return false
395+ }
396+ sha , ok := cm .Annotations [common .AnnotationCheckMountScriptSHA256 ]
397+ return ok && sha == expectedSHA256
398+ }
399+
350400func transformTemplateWithCacheDirDisabled (helper * helperData ) {
351401 template := helper .template
352402 template .FuseContainer .VolumeMounts = utils .TrimVolumeMounts (template .FuseContainer .VolumeMounts , cacheDirNames )
0 commit comments