Skip to content
Merged
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
8 changes: 3 additions & 5 deletions pkg/ddc/cache/engine/cm.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,15 @@
}

// generateRuntimeConfigData generate the data in the config map for runtime config
func (e *CacheEngine) generateRuntimeConfigData(ctx context.Context, runtime *datav1alpha1.CacheRuntime) (map[string]string, error) {

Check failure on line 102 in pkg/ddc/cache/engine/cm.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AZ_kj8aA5Y0uRHDRuJI9&open=AZ_kj8aA5Y0uRHDRuJI9&pullRequest=6157
dataset, err := utils.GetDatasetWithContext(ctx, e.Client, e.name, e.namespace)
if err != nil {
return nil, err
}

runtimeClass, err := e.getRuntimeClass(runtime.Spec.RuntimeClassName)
if err != nil {
return nil, err
}

var mounts []common.MountConfig
for _, m := range dataset.Spec.Mounts {
mountCg := common.MountConfig{
Expand Down Expand Up @@ -139,7 +137,7 @@
config.AccessModes = []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany}
}

if !runtime.Spec.Master.Disabled {
if runtimeClass.Topology.Master != nil && !runtime.Spec.Master.Disabled {
config.Master = &common.CacheRuntimeComponentConfig{
Enabled: true,
Name: common.GetCacheComponentName(e.name, common.ComponentTypeMaster),
Expand All @@ -153,7 +151,7 @@
}
}
}
if !runtime.Spec.Worker.Disabled {
if runtimeClass.Topology.Worker != nil && !runtime.Spec.Worker.Disabled {
config.Worker = &common.CacheRuntimeComponentConfig{
Enabled: true,
Name: common.GetCacheComponentName(e.name, common.ComponentTypeWorker),
Expand All @@ -169,7 +167,7 @@
// Extract tiered store configuration for worker
config.Worker.TieredStoreLevels = e.extractTieredStoreLevels(&runtime.Spec.Worker.TieredStore)
}
if !runtime.Spec.Client.Disabled {
if runtimeClass.Topology.Client != nil && !runtime.Spec.Client.Disabled {
config.Client = &common.CacheRuntimeComponentConfig{
Enabled: true,
Name: common.GetCacheComponentName(e.name, common.ComponentTypeClient),
Expand Down
106 changes: 106 additions & 0 deletions pkg/ddc/cache/engine/cm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package engine

import (
"context"
"strings"
"testing"

datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
Expand Down Expand Up @@ -207,6 +208,11 @@ func newCacheRuntimeForConfigMapTest() *datav1alpha1.CacheRuntime {
func newCacheRuntimeClassForConfigMapTest() *datav1alpha1.CacheRuntimeClass {
return &datav1alpha1.CacheRuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "test-class"},
Topology: &datav1alpha1.RuntimeTopology{
Master: &datav1alpha1.RuntimeComponentDefinition{},
Worker: &datav1alpha1.RuntimeComponentDefinition{},
Client: &datav1alpha1.RuntimeComponentDefinition{},
},
}
}

Expand All @@ -228,3 +234,103 @@ func newDatasetForConfigMapTest() *datav1alpha1.Dataset {
Status: datav1alpha1.DatasetStatus{Runtimes: []datav1alpha1.Runtime{{Name: "demo", Type: common.CacheRuntime}}},
}
}
func TestGenerateRuntimeConfigDataWithMissingComponentTopology(t *testing.T) {
testCases := map[string]struct {
topology *datav1alpha1.RuntimeTopology
enable func(runtime *datav1alpha1.CacheRuntime)
}{
"master topology undefined": {
topology: &datav1alpha1.RuntimeTopology{
Worker: &datav1alpha1.RuntimeComponentDefinition{},
Client: &datav1alpha1.RuntimeComponentDefinition{},
},
enable: func(r *datav1alpha1.CacheRuntime) { r.Spec.Master.Disabled = false },
},
"worker topology undefined": {
topology: &datav1alpha1.RuntimeTopology{
Master: &datav1alpha1.RuntimeComponentDefinition{},
Client: &datav1alpha1.RuntimeComponentDefinition{},
},
enable: func(r *datav1alpha1.CacheRuntime) { r.Spec.Worker.Disabled = false },
},
"client topology undefined": {
topology: &datav1alpha1.RuntimeTopology{
Master: &datav1alpha1.RuntimeComponentDefinition{},
Worker: &datav1alpha1.RuntimeComponentDefinition{},
},
enable: func(r *datav1alpha1.CacheRuntime) { r.Spec.Client.Disabled = false },
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
scheme := newCacheEngineTestScheme(t)
runtimeObj := newCacheRuntimeForConfigMapTest()
tc.enable(runtimeObj)
runtimeClass := newCacheRuntimeClassForConfigMapTest()
runtimeClass.Topology = tc.topology
dataset := newDatasetForConfigMapTest()
baseClient := fake.NewFakeClientWithScheme(scheme, runtimeObj, runtimeClass, dataset)
engine := &CacheEngine{Client: baseClient, name: "demo", namespace: "default"}

if _, err := engine.generateRuntimeConfigData(context.Background(), runtimeObj); err != nil {
t.Fatalf("expected no error, got %v", err)
}
})
}
}
func TestGenerateRuntimeConfigDataWithoutAnyComponent(t *testing.T) {
testCases := map[string]struct {
topology *datav1alpha1.RuntimeTopology
}{
"topology is nil": {topology: nil},
"topology declares no component": {topology: &datav1alpha1.RuntimeTopology{}},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
scheme := newCacheEngineTestScheme(t)
runtimeObj := newCacheRuntimeForConfigMapTest()
runtimeClass := newCacheRuntimeClassForConfigMapTest()
runtimeClass.Topology = tc.topology
dataset := newDatasetForConfigMapTest()
baseClient := fake.NewFakeClientWithScheme(scheme, runtimeObj, runtimeClass, dataset)
engine := &CacheEngine{Client: baseClient, name: "demo", namespace: "default"}

_, err := engine.generateRuntimeConfigData(context.Background(), runtimeObj)
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "at least one component should be defined") {
t.Fatalf("unexpected error message: %v", err)
}
})
}
}
func TestGenerateDataLoadValueFileWithNilTopology(t *testing.T) {
scheme := newCacheEngineTestScheme(t)
runtimeObj := newCacheRuntimeForConfigMapTest()
runtimeClass := &datav1alpha1.CacheRuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "test-class"},
Topology: nil,
DataOperationSpecs: []datav1alpha1.DataOperationSpec{
{Name: "DataLoad", Command: []string{"/usr/local/bin/dataload"}},
},
}
dataset := newDatasetForConfigMapTest()
dataload := &datav1alpha1.DataLoad{
ObjectMeta: metav1.ObjectMeta{Name: "test-dataload", Namespace: "default"},
Spec: datav1alpha1.DataLoadSpec{
Dataset: datav1alpha1.TargetDataset{Name: "demo", Namespace: "default"},
},
}

fakeClient := fake.NewFakeClientWithScheme(scheme, runtimeObj, runtimeClass, dataset, dataload)
engine := &CacheEngine{Client: fakeClient, name: "demo", namespace: "default"}
ctx := cruntime.ReconcileRequestContext{Client: fakeClient}

_, err := engine.generateDataLoadValueFile(ctx, dataload)
if err == nil {
t.Fatal("expected error when topology is nil, got nil")
}
}
5 changes: 3 additions & 2 deletions pkg/ddc/cache/engine/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
if err := e.Get(context.TODO(), key, &runtime); err != nil {
return nil, err
}

return &runtime, nil
}

Expand All @@ -82,13 +81,15 @@
if err := e.Get(context.TODO(), key, &runtimeClass); err != nil {
return nil, err
}

if err := validateRuntimeClassTopology(&runtimeClass); err != nil {
return nil, err
}
return &runtimeClass, nil
}

// getRuntimeInfo get the runtime info, may be called before dataset bound, so can not use base.GetRuntimeInfo but has
// the same processing logic.
func (e *CacheEngine) getRuntimeInfo() (base.RuntimeInfoInterface, error) {

Check failure on line 92 in pkg/ddc/cache/engine/runtime.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 18 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AaAIU0ifjGoFKvCIe3Xj&open=AaAIU0ifjGoFKvCIe3Xj&pullRequest=6157
if e.runtimeInfo == nil {
runtime, err := e.getRuntime()
if err != nil {
Expand Down
12 changes: 4 additions & 8 deletions pkg/ddc/cache/engine/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package engine

import (
"fmt"
"time"

datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
Expand Down Expand Up @@ -48,10 +47,8 @@ type RuntimeConfigVolumeConfig struct {
}

func (e *CacheEngine) transform(dataset *datav1alpha1.Dataset, runtime *datav1alpha1.CacheRuntime, runtimeClass *datav1alpha1.CacheRuntimeClass) (*common.CacheRuntimeValue, error) {

if runtimeClass.Topology == nil ||
(runtimeClass.Topology.Master == nil && runtimeClass.Topology.Worker == nil && runtimeClass.Topology.Client == nil) {
return nil, fmt.Errorf("at least one component should be defined in runtimeClass")
if err := validateRuntimeClassTopology(runtimeClass); err != nil {
return nil, err
}
defer utils.TimeTrack(time.Now(), "CacheRuntime.transform", "name", runtime.Name)

Expand Down Expand Up @@ -83,9 +80,8 @@ func (e *CacheEngine) transform(dataset *datav1alpha1.Dataset, runtime *datav1al
// getRuntimeStatusValue extracts minimal component status information from runtimeClass and runtime spec
// This is a lightweight alternative to transform() when only status update is needed
func (e *CacheEngine) getRuntimeStatusValue(runtime *datav1alpha1.CacheRuntime, runtimeClass *datav1alpha1.CacheRuntimeClass) (*common.CacheRuntimeStatusValue, error) {
if runtimeClass.Topology == nil ||
(runtimeClass.Topology.Master == nil && runtimeClass.Topology.Worker == nil && runtimeClass.Topology.Client == nil) {
return nil, fmt.Errorf("at least one component should be defined in runtimeClass")
if err := validateRuntimeClassTopology(runtimeClass); err != nil {
return nil, err
}

statusValue := &common.CacheRuntimeStatusValue{}
Expand Down
11 changes: 11 additions & 0 deletions pkg/ddc/cache/engine/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,20 @@
package engine

import (
"fmt"

datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
"github.com/fluid-cloudnative/fluid/pkg/runtime"
)

func (e *CacheEngine) Validate(runtime.ReconcileRequestContext) (err error) {
return nil
}

func validateRuntimeClassTopology(runtimeClass *datav1alpha1.CacheRuntimeClass) error {
if runtimeClass.Topology == nil ||
(runtimeClass.Topology.Master == nil && runtimeClass.Topology.Worker == nil && runtimeClass.Topology.Client == nil) {
return fmt.Errorf("at least one component should be defined in runtimeClass %s", runtimeClass.Name)
}
return nil
}
Loading