Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/ddc/jindo/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ const (
JindoFuseMountPath = "/jfs/jindofs-fuse"

DefaultJindoRuntimeImage = "registry.cn-shanghai.aliyuncs.com/jindofs/smartdata:3.8.0"

WorkerContainerName = "jindofs-worker"
)
44 changes: 44 additions & 0 deletions pkg/ddc/jindo/image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2022 The Fluid Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package jindo

import (
"fmt"

"github.com/fluid-cloudnative/fluid/pkg/common"
"github.com/fluid-cloudnative/fluid/pkg/utils/docker"
)

// resolveSmartDataImage returns the full image string for the SmartData container
func resolveSmartDataImage() string {
var (
defaultImage = "registry.cn-shanghai.aliyuncs.com/jindofs/smartdata"
defaultTag = "3.8.0"
)
Comment on lines +28 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The default image and tag are hardcoded here, which duplicates the DefaultJindoRuntimeImage constant defined in pkg/ddc/jindo/const.go. To avoid duplication and improve maintainability, it's better to derive the default image and tag from the constant.

	defaultImage, defaultTag := docker.ParseDockerImage(DefaultJindoRuntimeImage)


image := docker.GetImageRepoFromEnv(common.JindoSmartDataImageEnv)
tag := docker.GetImageTagFromEnv(common.JindoSmartDataImageEnv)

if len(image) == 0 {
image = defaultImage
}
if len(tag) == 0 {
tag = defaultTag
}

return fmt.Sprintf("%s:%s", image, tag)
}
65 changes: 63 additions & 2 deletions pkg/ddc/jindo/sync_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,70 @@ limitations under the License.

package jindo

import cruntime "github.com/fluid-cloudnative/fluid/pkg/runtime"
import (
"k8s.io/apimachinery/pkg/types"

"github.com/fluid-cloudnative/fluid/pkg/ctrl"
cruntime "github.com/fluid-cloudnative/fluid/pkg/runtime"
"github.com/fluid-cloudnative/fluid/pkg/utils"
)

// SyncRuntime syncs the runtime spec
func (e *JindoEngine) SyncRuntime(ctx cruntime.ReconcileRequestContext) (changed bool, err error) {
return
if e.Client == nil {
e.Log.V(1).Info("Client is nil, skipping SyncRuntime")
Comment on lines +29 to +30
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nil check for the Client protects against panic, but silently returns without logging at a higher level. While there is a V(1) debug log, in production scenarios where Client should never be nil, this could mask a serious initialization issue. Consider using a higher log level (V(0) or Error) if this condition occurs in non-test scenarios, or add a comment explaining that this is specifically for unit test compatibility.

Suggested change
if e.Client == nil {
e.Log.V(1).Info("Client is nil, skipping SyncRuntime")
// In normal production flows, e.Client is expected to be non-nil.
// This guard primarily exists for unit tests where the Client is not initialized.
if e.Client == nil {
e.Log.Info("Client is nil, skipping SyncRuntime; this should only occur in unit tests")

Copilot uses AI. Check for mistakes.
return false, nil
}

// 1. Get the workers StatefulSet
workers, err := ctrl.GetWorkersAsStatefulset(e.Client,
types.NamespacedName{Namespace: e.namespace, Name: e.getWorkerName()})
if err != nil {
if utils.IgnoreNotFound(err) == nil {
e.Log.V(1).Info("Workers not found", "name", e.getWorkerName())
return false, nil
}
return false, err
}

// 2. Extract current image
var currentImage string
var containerIndex int = -1
for i, container := range workers.Spec.Template.Spec.Containers {
if container.Name == WorkerContainerName {
currentImage = container.Image
containerIndex = i
break
}
}

if len(currentImage) == 0 || containerIndex == -1 {
e.Log.V(1).Info("Worker container not found", "name", e.getWorkerName())
return false, nil
}

// 3. Compute desired image using shared helper
desiredImage := resolveSmartDataImage()

// 4. Compare desired image vs current image
if currentImage != desiredImage {
e.Log.Info("Image drift detected, triggering rolling upgrade", "current", currentImage, "desired", desiredImage)

// Update the image
workersToUpdate := workers.DeepCopy()
workersToUpdate.Spec.Template.Spec.Containers[containerIndex].Image = desiredImage

err = e.Client.Update(ctx.Context, workersToUpdate)
if err != nil {
e.Log.Error(err, "Failed to update worker image", "desired", desiredImage)
return false, err
}

e.Log.Info("Successfully triggered rolling upgrade for worker StatefulSet", "name", e.getWorkerName())

// Return false, nil to continue reconciliation without short-circuiting
return false, nil
Comment on lines +80 to +81
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new SyncRuntime implementation returns false for the changed parameter even when an image update is applied. According to the function signature, changed should indicate whether the runtime spec was changed. When an image update is triggered (line 72), the function should return true instead of false to properly indicate that a change was made. This would allow the reconciliation loop to properly track that a change occurred.

Suggested change
// Return false, nil to continue reconciliation without short-circuiting
return false, nil
// Indicate that a change was made so the reconciliation loop can track it
return true, nil

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function returns false for the changed flag even after successfully updating the worker StatefulSet. While this avoids an immediate requeue, it's inconsistent with the semantics of the changed return value and other runtime engine implementations, which typically return true to signal that a change was made. Returning true would make the control flow clearer and more consistent across the codebase.

Suggested change
return false, nil
return true, nil

}

return false, nil
}
19 changes: 9 additions & 10 deletions pkg/ddc/jindo/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,20 +544,19 @@ func (e *JindoEngine) transformFuseArg(runtime *datav1alpha1.JindoRuntime, datas

func (e *JindoEngine) getSmartDataConfigs() (image, tag, dnsServer string) {
var (
defaultImage = "registry.cn-shanghai.aliyuncs.com/jindofs/smartdata"
defaultTag = "3.8.0"
defaultDnsServer = "1.1.1.1"
)

image = docker.GetImageRepoFromEnv(common.JindoSmartDataImageEnv)
tag = docker.GetImageTagFromEnv(common.JindoSmartDataImageEnv)
dnsServer = os.Getenv(common.JindoDnsServer)
if len(image) == 0 {
image = defaultImage
}
if len(tag) == 0 {
tag = defaultTag
fullImage := resolveSmartDataImage()
lastColon := strings.LastIndex(fullImage, ":")
if lastColon != -1 {
image = fullImage[:lastColon]
tag = fullImage[lastColon+1:]
} else {
image = fullImage
}
Comment on lines +551 to 557
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation for splitting the image and tag might not correctly handle image names that include a port number (e.g., my-registry:5000/my-image:tag). The docker.ParseDockerImage utility function is designed to handle such cases correctly. Using it would make the code more robust and consistent with other parts of the codebase.

Suggested change
lastColon := strings.LastIndex(fullImage, ":")
if lastColon != -1 {
image = fullImage[:lastColon]
tag = fullImage[lastColon+1:]
} else {
image = fullImage
}
image, tag = docker.ParseDockerImage(fullImage)


dnsServer = os.Getenv(common.JindoDnsServer)
if len(dnsServer) == 0 {
dnsServer = defaultDnsServer
}
Expand Down
12 changes: 11 additions & 1 deletion pkg/utils/testutil/unit_test_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,20 @@ limitations under the License.

package testutil

import "os"
import (
"os"
"strings"
)

const FluidUnitTestEnv = "FLUID_UNIT_TEST"

func init() {
// Automatically detect if running inside a test binary
if strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe") {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The automatic test detection checks for both ".test" and ".test.exe" suffixes which is good for cross-platform support. However, the logic uses os.Args[0] which contains the program name. On some systems or in certain contexts (e.g., when running through a wrapper script), this might not be the actual executable path. Consider adding a defensive check to ensure os.Args is not empty before accessing os.Args[0], though in practice this should always have at least one element in Go.

Suggested change
if strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe") {
if len(os.Args) > 0 && (strings.HasSuffix(os.Args[0], ".test") || strings.HasSuffix(os.Args[0], ".test.exe")) {

Copilot uses AI. Check for mistakes.
os.Setenv(FluidUnitTestEnv, "true")
}
}

func IsUnitTest() bool {
_, exists := os.LookupEnv(FluidUnitTestEnv)
return exists
Expand Down
25 changes: 12 additions & 13 deletions vendor/github.com/agiledragon/gomonkey/v2/jmp_amd64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 19 additions & 19 deletions vendor/github.com/agiledragon/gomonkey/v2/modify_binary_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/github.com/beorn7/perks/quantile/stream.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions vendor/github.com/blang/semver/v4/range.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/github.com/davecgh/go-spew/spew/bypass.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/github.com/davecgh/go-spew/spew/bypasssafe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 15 additions & 15 deletions vendor/github.com/davecgh/go-spew/spew/config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading