Repository: fluid-cloudnative/fluid
Pull request #3789 (2024-04-03 15:12:07)

Fix copyright year in init.go
### Ⅰ. Describe what this PR does
This pr is to fix copyright year in ./cmd/alluxio/app/init.go

### Ⅱ. Does this pull request fix one issue?
NONE

### Ⅲ. List the added test cases (unit test/integration test) if any, please explain if no tests are needed.

### Ⅳ. Describe how to verify it

### Ⅴ. Special notes for reviews

fluid-e2e-bot[bot]: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please assign cheyang for approval by writing `/assign @cheyang` in a comment. For more information see:[The Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=fluid-cloudnative%2Ffluid).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/fluid-cloudnative/fluid/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["cheyang"]} -->
fluid-e2e-bot[bot]: Hi @NolanWY. Thanks for your PR.

I'm waiting for a [fluid-cloudnative](https://github.com/orgs/fluid-cloudnative/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://github.com/orgs/fluid-cloudnative/people) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=fluid-cloudnative%2Ffluid).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>


Patch:
diff --git a/api/v1alpha1/dataprocess_types.go b/api/v1alpha1/dataprocess_types.go
index 70b426ef..5f4b44f7 100644
--- a/api/v1alpha1/dataprocess_types.go
+++ b/api/v1alpha1/dataprocess_types.go
@@ -96,7 +96,7 @@ type ScriptProcessor struct {
 // DataProcessSpec defines the desired state of DataProcess
 type DataProcessSpec struct {
 	// Dataset specifies the target dataset and its mount path.
-	// +requried
+	// +required
 	Dataset TargetDatasetWithMountPath `json:"dataset"`
 
 	// Processor specify how to process data.
diff --git a/charts/fluid/fluid/Chart.yaml b/charts/fluid/fluid/Chart.yaml
index c53aa99d..45df905a 100644
--- a/charts/fluid/fluid/Chart.yaml
+++ b/charts/fluid/fluid/Chart.yaml
@@ -18,7 +18,7 @@ version: 1.0.0
 
 # This is the version number of the application being deployed. This version number should be
 # incremented each time you make changes to the application.
-appVersion: 1.0.0-10382d2
+appVersion: 1.0.0-1cb79cf
 home: https://github.com/fluid-cloudnative/fluid
 keywords:
   - category:data
diff --git a/charts/fluid/fluid/templates/controller/vineyardruntime_controller.yaml b/charts/fluid/fluid/templates/controller/vineyardruntime_controller.yaml
index efaab4f0..55b26d52 100644
--- a/charts/fluid/fluid/templates/controller/vineyardruntime_controller.yaml
+++ b/charts/fluid/fluid/templates/controller/vineyardruntime_controller.yaml
@@ -60,6 +60,18 @@ spec:
         - name: MOUNT_ROOT
           value: {{ .Values.runtime.mountRoot | quote }}
         {{- end }}
+        {{- if .Values.runtime.vineyard.master.image }}
+        - name: VINEYARD_MASTER_IMAGE_ENV
+          value: {{ .Values.runtime.vineyard.master.image | quote }}
+        {{- end }}
+        {{- if .Values.runtime.vineyard.worker.image }}
+        - name: VINEYARD_WORKER_IMAGE_ENV
+          value: {{ .Values.runtime.vineyard.worker.image | quote }}
+        {{- end }}
+        {{- if .Values.runtime.vineyard.fuse.image }}
+        - name: VINEYARD_FUSE_IMAGE_ENV
+          value: {{ .Values.runtime.vineyard.fuse.image | quote }}
+        {{- end }}
         {{- if .Values.runtime.syncRetryDuration }}
         - name: FLUID_SYNC_RETRY_DURATION
           value: {{ .Values.runtime.syncRetryDuration | quote }}
diff --git a/charts/fluid/fluid/values.yaml b/charts/fluid/fluid/values.yaml
index fcac8ff7..948155d8 100644
--- a/charts/fluid/fluid/values.yaml
+++ b/charts/fluid/fluid/values.yaml
@@ -12,7 +12,7 @@ crdUpgrade:
   enabled: true
   # This sets the time-to-live (TTL) for crd-upgrade jobs. Default is 259200 seconds (3 days).
   ttlSecondsAfterFinished: 259200 
-  image: fluidcloudnative/fluid-crd-upgrader:v1.0.0-10382d2
+  image: fluidcloudnative/fluid-crd-upgrader:v1.0.0-1cb79cf
 
 ##  if unspecified, will use built-in variable `.Release.Namespace`.
 namespace: fluid-system
@@ -25,7 +25,7 @@ dataset:
   tolerations:
     - operator: Exists
   controller:
-    image: fluidcloudnative/dataset-controller:v1.0.0-10382d2
+    image: fluidcloudnative/dataset-controller:v1.0.0-1cb79cf
 
 csi:
   tolerations:
@@ -36,7 +36,7 @@ csi:
   registrar:
     image: fluidcloudnative/csi-node-driver-registrar:v2.3.0
   plugins:
-    image: fluidcloudnative/fluid-csi:v1.0.0-10382d2
+    image: fluidcloudnative/fluid-csi:v1.0.0-1cb79cf
   kubelet:
     kubeConfigFile: /etc/kubernetes/kubelet.conf
     certDir: /var/lib/kubelet/pki
@@ -63,7 +63,7 @@ runtime:
     init:
       image: fluidcloudnative/init-users:v0.9.0
     controller:
-      image: fluidcloudnative/alluxioruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/alluxioruntime-controller:v1.0.0-1cb79cf
     runtime:
       image: alluxio/alluxio-dev:2.9.0
     fuse:
@@ -84,7 +84,7 @@ runtime:
     fuse:
       image: registry.cn-shanghai.aliyuncs.com/jindofs/jindo-fuse:6.2.0
     controller:
-      image: fluidcloudnative/jindoruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/jindoruntime-controller:v1.0.0-1cb79cf
     init:
       portCheck:
         enabled: false
@@ -100,7 +100,7 @@ runtime:
     init:
       image: fluidcloudnative/init-users:v0.9.0
     controller:
-      image: fluidcloudnative/goosefsruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/goosefsruntime-controller:v1.0.0-1cb79cf
     runtime:
       image: ccr.ccs.tencentyun.com/qcloud/goosefs:v1.2.0
     fuse:
@@ -112,7 +112,7 @@ runtime:
     enabled: false
     runtimeWorkers: 3
     controller:
-      image: fluidcloudnative/juicefsruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/juicefsruntime-controller:v1.0.0-1cb79cf
     fuse:
       ceimage: juicedata/juicefs-fuse:ce-v1.1.0-rc1
       eeimage: juicedata/juicefs-fuse:ee-4.9.16
@@ -122,7 +122,7 @@ runtime:
       - operator: Exists
     enabled: false
     controller:
-      image: fluidcloudnative/thinruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/thinruntime-controller:v1.0.0-1cb79cf
     fuse:
       configStorage: configmap
   efc:
@@ -131,7 +131,7 @@ runtime:
       - operator: Exists
     enabled: false
     controller:
-      image: fluidcloudnative/efcruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/efcruntime-controller:v1.0.0-1cb79cf
       imagePullPolicy: Always
     init:
       image: registry.cn-zhangjiakou.aliyuncs.com/nascache/init-alifuse:v1.2.2-19dcee9
@@ -147,12 +147,18 @@ runtime:
       - operator: Exists
     enabled: false
     controller:
-      image: fluidcloudnative/vineyardruntime-controller:v1.0.0-10382d2
+      image: fluidcloudnative/vineyardruntime-controller:v1.0.0-1cb79cf
       imagePullPolicy: Always
+    master:
+      image: bitnami/etcd:3.5.10
+    worker:
+      image: vineyardcloudnative/vineyardd:v0.21.5
+    fuse:
+      image: vineyardcloudnative/vineyard-fluid-fuse:v0.21.5
 
 webhook:
   enabled: true
-  image: fluidcloudnative/fluid-webhook:v1.0.0-10382d2
+  image: fluidcloudnative/fluid-webhook:v1.0.0-1cb79cf
   replicas: 1
   timeoutSeconds: 15
   reinvocationPolicy: IfNeeded
@@ -202,4 +208,4 @@ fluidapp:
   tolerations:
     - operator: Exists
   controller:
-    image: fluidcloudnative/application-controller:v1.0.0-10382d2
+    image: fluidcloudnative/application-controller:v1.0.0-1cb79cf
diff --git a/cmd/alluxio/app/init.go b/cmd/alluxio/app/init.go
index d129a318..f492a467 100644
--- a/cmd/alluxio/app/init.go
+++ b/cmd/alluxio/app/init.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Fluid Authors.
+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.
diff --git a/cmd/alluxio/app/version.go b/cmd/alluxio/app/version.go
index c1003351..f2270e40 100644
--- a/cmd/alluxio/app/version.go
+++ b/cmd/alluxio/app/version.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Fluid Authors.
+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.
diff --git a/docs/zh/operation/monitoring.md b/docs/zh/operation/monitoring.md
index e0c358f4..0d2387d3 100644
--- a/docs/zh/operation/monitoring.md
+++ b/docs/zh/operation/monitoring.md
@@ -129,12 +129,12 @@ spec:
         quota: 1Gi
         high: "0.95"
         low: "0.7"
-  # 默认在v0.5.0版本之后，alluxio runtime已经开启了Prometheous数据，如果需要关闭可以主动设置disablePrometheus: true
+  # 默认在v0.5.0版本之后，alluxio runtime已经开启了Prometheus数据，如果需要关闭可以主动设置disablePrometheus: true
   # disablePrometheus: false  
 EOF
 ```
 
-> 注意：默认Prometheous是开启的。如果需要关闭Prometheous，可以设置 disablePrometheus: true, 默认为 false
+> 注意：默认Prometheus是开启的。如果需要关闭Prometheus，可以设置 disablePrometheus: true, 默认为 false
 
 6. 查看监控
 在 grafana HOME 中知道名为Fluid-Prometheus-Grafana-Monitor视图即可，如下所示:
diff --git a/pkg/common/vineyard.go b/pkg/common/vineyard.go
index cbf0d336..99b3178c 100644
--- a/pkg/common/vineyard.go
+++ b/pkg/common/vineyard.go
@@ -21,6 +21,12 @@ const (
 
 	VineyardChart = VineyardRuntime
 
+	VineyardMasterImageEnv = "VINEYARD_MASTER_IMAGE_ENV"
+
+	VineyardWorkerImageEnv = "VINEYARD_WORKER_IMAGE_ENV"
+
+	VineyardFuseImageEnv = "VINEYARD_FUSE_IMAGE_ENV"
+
 	VineyardFuseIsGlobal = true
 
 	DefaultVineyardMasterImage = "bitnami/etcd:3.5.10"
diff --git a/pkg/ddc/jindocache/transform.go b/pkg/ddc/jindocache/transform.go
index 306b4b46..784661b6 100644
--- a/pkg/ddc/jindocache/transform.go
+++ b/pkg/ddc/jindocache/transform.go
@@ -270,6 +270,10 @@ func (e *JindoCacheEngine) transformMaster(runtime *datav1alpha1.JindoRuntime, m
 		// to parse cacheset
 		cachesetName := mount.Name
 		cachesetPath := mount.MountPoint
+		if strings.HasPrefix(mount.MountPoint, common.VolumeScheme.String()) {
+			ufsVolumesPath := utils.UFSPathBuilder{}.GenLocalStoragePath(mount)
+			cachesetPath = "local://" + ufsVolumesPath
+		}
 		cacheStrategy := "DISTRIBUTED"
 		metaPolicy := "ALWAYS"
 		readCacheReplica := 1
@@ -451,11 +455,11 @@ func (e *JindoCacheEngine) transformMaster(runtime *datav1alpha1.JindoRuntime, m
 			if secretMountSupport {
 				value.Secret = secretKeyRef.Name
 				if key == "fs."+mountType+".accessKeyId" {
-					value.SecretKey = key
+					value.SecretKey = secretKeyRef.Key
 					e.Log.Info("Get %s From %s!", key, secretKeyRef.Name)
 				}
 				if key == "fs."+mountType+".accessKeySecret" {
-					value.SecretValue = key
+					value.SecretValue = secretKeyRef.Key
 					e.Log.Info("Get %s From %s!", key, secretKeyRef.Name)
 				}
 			} else {
diff --git a/pkg/ddc/vineyard/transform.go b/pkg/ddc/vineyard/transform.go
index 750cbdd1..d6a777cb 100644
--- a/pkg/ddc/vineyard/transform.go
+++ b/pkg/ddc/vineyard/transform.go
@@ -15,9 +15,10 @@ package vineyard
 
 import (
 	"fmt"
-	"github.com/fluid-cloudnative/fluid/pkg/common"
 	"time"
 
+	"github.com/fluid-cloudnative/fluid/pkg/common"
+
 	datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
 	"github.com/fluid-cloudnative/fluid/pkg/utils"
 	"github.com/fluid-cloudnative/fluid/pkg/utils/transfromer"
diff --git a/pkg/ddc/vineyard/utils.go b/pkg/ddc/vineyard/utils.go
index cdcf2c6b..4b1f68e0 100644
--- a/pkg/ddc/vineyard/utils.go
+++ b/pkg/ddc/vineyard/utils.go
@@ -25,6 +25,7 @@ import (
 	datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
 	"github.com/fluid-cloudnative/fluid/pkg/common"
 	"github.com/fluid-cloudnative/fluid/pkg/utils"
+	"github.com/fluid-cloudnative/fluid/pkg/utils/docker"
 )
 
 // getRuntime gets the vineyard runtime
@@ -128,20 +129,26 @@ func (e *VineyardEngine) parseMasterImage(image string, tag string, imagePullPol
 	}
 
 	if len(image) == 0 {
-		masterImageInfo := strings.Split(common.DefaultVineyardMasterImage, ":")
-		if len(masterImageInfo) < 1 {
-			panic("invalid default vineyard master image!")
-		} else {
-			image = masterImageInfo[0]
+		image = docker.GetImageRepoFromEnv(common.VineyardMasterImageEnv)
+		if len(image) == 0 {
+			masterImageInfo := strings.Split(common.DefaultVineyardMasterImage, ":")
+			if len(masterImageInfo) < 1 {
+				panic("invalid default vineyard master image!")
+			} else {
+				image = masterImageInfo[0]
+			}
 		}
 	}
 
 	if len(tag) == 0 {
-		masterImageInfo := strings.Split(common.DefaultVineyardMasterImage, ":")
-		if len(masterImageInfo) < 2 {
-			panic("invalid default vineyard master image!")
-		} else {
-			tag = masterImageInfo[1]
+		tag = docker.GetImageTagFromEnv(common.VineyardMasterImageEnv)
+		if len(tag) == 0 {
+			masterImageInfo := strings.Split(common.DefaultVineyardMasterImage, ":")
+			if len(masterImageInfo) < 2 {
+				panic("invalid default vineyard master image!")
+			} else {
+				tag = masterImageInfo[1]
+			}
 		}
 	}
 
@@ -154,20 +161,26 @@ func (e *VineyardEngine) parseWorkerImage(image string, tag string, imagePullPol
 	}
 
 	if len(image) == 0 {
-		workerImageInfo := strings.Split(common.DefaultVineyardWorkerImage, ":")
-		if len(workerImageInfo) < 1 {
-			panic("invalid default vineyard worker image!")
-		} else {
-			image = workerImageInfo[0]
+		image = docker.GetImageRepoFromEnv(common.VineyardWorkerImageEnv)
+		if len(image) == 0 {
+			workerImageInfo := strings.Split(common.DefaultVineyardWorkerImage, ":")
+			if len(workerImageInfo) < 1 {
+				panic("invalid default vineyard worker image!")
+			} else {
+				image = workerImageInfo[0]
+			}
 		}
 	}
 
 	if len(tag) == 0 {
-		workerImageInfo := strings.Split(common.DefaultVineyardWorkerImage, ":")
-		if len(workerImageInfo) < 2 {
-			panic("invalid default vineyard worker image!")
-		} else {
-			tag = workerImageInfo[1]
+		tag = docker.GetImageTagFromEnv(common.VineyardWorkerImageEnv)
+		if len(tag) == 0 {
+			workerImageInfo := strings.Split(common.DefaultVineyardWorkerImage, ":")
+			if len(workerImageInfo) < 2 {
+				panic("invalid default vineyard worker image!")
+			} else {
+				tag = workerImageInfo[1]
+			}
 		}
 	}
 
@@ -180,20 +193,26 @@ func (e *VineyardEngine) parseFuseImage(image string, tag string, imagePullPolic
 	}
 
 	if len(image) == 0 {
-		fuseImageInfo := strings.Split(common.DefultVineyardFuseImage, ":")
-		if len(fuseImageInfo) < 1 {
-			panic("invalid default vineyard fuse image!")
-		} else {
-			image = fuseImageInfo[0]
+		image = docker.GetImageRepoFromEnv(common.VineyardFuseImageEnv)
+		if len(image) == 0 {
+			fuseImageInfo := strings.Split(common.DefultVineyardFuseImage, ":")
+			if len(fuseImageInfo) < 1 {
+				panic("invalid default vineyard fuse image!")
+			} else {
+				image = fuseImageInfo[0]
+			}
 		}
 	}
 
 	if len(tag) == 0 {
-		fuseImageInfo := strings.Split(common.DefultVineyardFuseImage, ":")
-		if len(fuseImageInfo) < 2 {
-			panic("invalid default vineyard fuse image!")
-		} else {
-			tag = fuseImageInfo[1]
+		tag = docker.GetImageTagFromEnv(common.VineyardFuseImageEnv)
+		if len(tag) == 0 {
+			fuseImageInfo := strings.Split(common.DefultVineyardFuseImage, ":")
+			if len(fuseImageInfo) < 2 {
+				panic("invalid default vineyard fuse image!")
+			} else {
+				tag = fuseImageInfo[1]
+			}
 		}
 	}
 


Test patch:
diff --git a/pkg/ddc/jindocache/transform_test.go b/pkg/ddc/jindocache/transform_test.go
index d437b891..670438bc 100644
--- a/pkg/ddc/jindocache/transform_test.go
+++ b/pkg/ddc/jindocache/transform_test.go
@@ -19,6 +19,8 @@ package jindocache
 import (
 	"os"
 	"reflect"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 	"testing"
 
 	datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
@@ -1370,3 +1372,92 @@ func TestJindoCacheEngine_transformCacheSet(t *testing.T) {
 		})
 	}
 }
+
+func TestJindoEngine_transformSecret(t *testing.T) {
+	jindocacheSecret := &corev1.Secret{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "test",
+			Namespace: "fluid",
+		},
+		Data: map[string][]byte{
+			"AccessKeyId":     []byte("test"),
+			"AccessKeySecret": []byte("test"),
+		},
+	}
+	testObjs := []runtime.Object{}
+	testObjs = append(testObjs, (*jindocacheSecret).DeepCopy())
+
+	client := fake.NewFakeClientWithScheme(testScheme, testObjs...)
+	engine := JindoCacheEngine{
+		name:      "test",
+		namespace: "fluid",
+		Client:    client,
+		Log:       fake.NullLogger(),
+		runtime: &datav1alpha1.JindoRuntime{
+			Spec: datav1alpha1.JindoRuntimeSpec{
+				Fuse: datav1alpha1.JindoFuseSpec{},
+			},
+		},
+	}
+	ctrl.SetLogger(zap.New(func(o *zap.Options) {
+		o.Development = true
+	}))
+
+	var tests = []struct {
+		runtime *datav1alpha1.JindoRuntime
+		dataset *datav1alpha1.Dataset
+		value   *Jindo
+	}{
+		{&datav1alpha1.JindoRuntime{
+			Spec: datav1alpha1.JindoRuntimeSpec{
+				Fuse: datav1alpha1.JindoFuseSpec{},
+				Worker: datav1alpha1.JindoCompTemplateSpec{
+					Replicas:     2,
+					Resources:    corev1.ResourceRequirements{},
+					Env:          nil,
+					NodeSelector: nil,
+				},
+			},
+		}, &datav1alpha1.Dataset{
+			Spec: datav1alpha1.DatasetSpec{
+				Mounts: []datav1alpha1.Mount{{
+					MountPoint: "pvc:///mnt/test",
+					Name:       "test",
+					EncryptOptions: []datav1alpha1.EncryptOption{{
+						Name: "fs.oss.accessKeyId",
+						ValueFrom: datav1alpha1.EncryptOptionSource{
+							SecretKeyRef: datav1alpha1.SecretKeySelector{
+								Name: "test",
+								Key:  "AccessKeyId",
+							},
+						},
+					},
+						{
+							Name: "fs.oss.accessKeySecret",
+							ValueFrom: datav1alpha1.EncryptOptionSource{
+								SecretKeyRef: datav1alpha1.SecretKeySelector{
+									Name: "test",
+									Key:  "AccessKeySecret",
+								},
+							},
+						}},
+				}},
+			},
+		}, &Jindo{}},
+	}
+	for _, test := range tests {
+		err := engine.transformMaster(test.runtime, "/test", test.value, test.dataset, true)
+		if err != nil {
+			t.Errorf("error %v", err)
+		}
+		if test.value.SecretKey != "AccessKeyId" {
+			t.Errorf("expected value AccessKeyId, but got %v", test.value.SecretKey)
+		}
+		if test.value.SecretValue != "AccessKeySecret" {
+			t.Errorf("expected value AccessKeyId, but got %v", test.value.SecretKey)
+		}
+		if test.value.Secret != "test" {
+			t.Errorf("expected value AccessKeyId, but got %v", test.value.SecretKey)
+		}
+	}
+}
diff --git a/pkg/ddc/vineyard/transform_test.go b/pkg/ddc/vineyard/transform_test.go
index 3c626d3c..a6c15e6e 100755
--- a/pkg/ddc/vineyard/transform_test.go
+++ b/pkg/ddc/vineyard/transform_test.go
@@ -14,7 +14,9 @@ limitations under the License.
 package vineyard
 
 import (
+	"os"
 	"reflect"
+	"strings"
 	"testing"
 
 	datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
@@ -37,25 +39,47 @@ func TestTransformFuse(t *testing.T) {
 		o.Development = true
 	}))
 
-	var tests = []struct {
+	var tests = map[string]struct {
 		runtime   *datav1alpha1.VineyardRuntime
 		value     *Vineyard
 		expect    []string
 		expectEnv map[string]string
 	}{
-		{&datav1alpha1.VineyardRuntime{
-			Spec: datav1alpha1.VineyardRuntimeSpec{
-				Fuse: datav1alpha1.VineyardSockSpec{
-					Image:           "dummy-fuse-image",
-					ImageTag:        "dummy-tag",
-					ImagePullPolicy: "IfNotPresent",
-					Env:             map[string]string{"TEST_ENV": "true"},
-					CleanPolicy:     "OnRuntimeDeleted",
+		"test image, imageTag and pullPolicy": {
+			runtime: &datav1alpha1.VineyardRuntime{
+				Spec: datav1alpha1.VineyardRuntimeSpec{
+					Fuse: datav1alpha1.VineyardSockSpec{
+						Image:           "dummy-fuse-image",
+						ImageTag:        "dummy-tag",
+						ImagePullPolicy: "IfNotPresent",
+						Env:             map[string]string{"TEST_ENV": "true"},
+						CleanPolicy:     "OnRuntimeDeleted",
+					},
+				},
+			},
+			value:     &Vineyard{},
+			expect:    []string{"dummy-fuse-image", "dummy-tag", "IfNotPresent", "OnRuntimeDeleted"},
+			expectEnv: map[string]string{"TEST_ENV": "true"},
+		},
+		"test image, imageTag and pullPolicy from env": {
+			runtime: &datav1alpha1.VineyardRuntime{
+				Spec: datav1alpha1.VineyardRuntimeSpec{
+					Fuse: datav1alpha1.VineyardSockSpec{
+						ImagePullPolicy: "IfNotPresent",
+						Env:             map[string]string{"TEST_ENV": "true"},
+						CleanPolicy:     "OnRuntimeDeleted",
+					},
 				},
 			},
-		}, &Vineyard{}, []string{"dummy-fuse-image", "dummy-tag", "IfNotPresent", "OnRuntimeDeleted"}, map[string]string{"TEST_ENV": "true"}},
+			value:     &Vineyard{},
+			expect:    []string{"image-from-env", "image-tag-from-env", "IfNotPresent", "OnRuntimeDeleted"},
+			expectEnv: map[string]string{"TEST_ENV": "true"},
+		},
 	}
-	for _, test := range tests {
+	for k, test := range tests {
+		if strings.Contains(k, "env") {
+			os.Setenv("VINEYARD_FUSE_IMAGE_ENV", "image-from-env:image-tag-from-env")
+		}
 		engine := &VineyardEngine{}
 		engine.Log = ctrl.Log
 		engine.transformFuse(test.runtime, test.value)
@@ -75,6 +99,9 @@ func TestTransformFuse(t *testing.T) {
 		if !reflect.DeepEqual(test.value.Fuse.Env, test.expectEnv) {
 			t.Errorf("Expected Fuse Env %v, got %v", test.expectEnv, test.value.Fuse.Env)
 		}
+		if strings.Contains(k, "env") {
+			os.Unsetenv("VINEYARD_FUSE_IMAGE_ENV")
+		}
 	}
 }
 
@@ -103,11 +130,32 @@ func TestTransformMaster(t *testing.T) {
 				},
 			},
 		},
+		"test image, imageTag and pullPolicy from env": {
+			runtime: &datav1alpha1.VineyardRuntime{
+				Spec: datav1alpha1.VineyardRuntimeSpec{
+					Master: datav1alpha1.MasterSpec{
+						VineyardCompTemplateSpec: datav1alpha1.VineyardCompTemplateSpec{
+							ImagePullPolicy: "IfNotPresent",
+						},
+					},
+				},
+			},
+			wantValue: &Vineyard{
+				Master: Master{
+					Image:           "image-from-env",
+					ImageTag:        "image-tag-from-env",
+					ImagePullPolicy: "IfNotPresent",
+				},
+			},
+		},
 	}
 
 	engine := &VineyardEngine{Log: fake.NullLogger()}
 	ds := &datav1alpha1.Dataset{}
 	for k, v := range testCases {
+		if strings.Contains(k, "env") {
+			os.Setenv("VINEYARD_MASTER_IMAGE_ENV", "image-from-env:image-tag-from-env")
+		}
 		gotValue := &Vineyard{}
 		if err := engine.transformMasters(v.runtime, ds, gotValue); err == nil {
 			if gotValue.Master.Image != v.wantValue.Master.Image {
@@ -132,6 +180,9 @@ func TestTransformMaster(t *testing.T) {
 				)
 			}
 		}
+		if strings.Contains(k, "env") {
+			os.Unsetenv("VINEYARD_MASTER_IMAGE_ENV")
+		}
 	}
 }
 
@@ -160,10 +211,33 @@ func TestTransformWorker(t *testing.T) {
 				},
 			},
 		},
+		"test replicas, image, imageTag and pullPolicy from env": {
+			runtime: &datav1alpha1.VineyardRuntime{
+				Spec: datav1alpha1.VineyardRuntimeSpec{
+					Replicas: 3,
+					Worker: datav1alpha1.VineyardCompTemplateSpec{
+						Replicas:        2,
+						Image:           "test-image",
+						ImageTag:        "test-tag",
+						ImagePullPolicy: "IfNotPresent",
+					},
+				},
+			},
+			wantValue: &Vineyard{
+				Worker: Worker{
+					Image:           "image-from-env",
+					ImageTag:        "image-tag-from-env",
+					ImagePullPolicy: "IfNotPresent",
+				},
+			},
+		},
 	}
 
 	engine := &VineyardEngine{Log: fake.NullLogger()}
 	for k, v := range testCases {
+		if strings.Contains(k, "env") {
+			os.Setenv("VINEYARD_WORKER_IMAGE_ENV", "image-from-env:image-tag-from-env")
+		}
 		gotValue := &Vineyard{}
 		engine.runtimeInfo, _ = base.BuildRuntimeInfo("test", "test", "vineyard", v.runtime.Spec.TieredStore)
 		if err := engine.transformWorkers(v.runtime, gotValue); err == nil {
@@ -196,6 +270,9 @@ func TestTransformWorker(t *testing.T) {
 				)
 			}
 		}
+		if strings.Contains(k, "env") {
+			os.Unsetenv("VINEYARD_WORKER_IMAGE_ENV")
+		}
 	}
 }