Skip to content

Commit

Permalink
add ut
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Rookie committed Sep 9, 2024
1 parent 9c29599 commit 21ef324
Show file tree
Hide file tree
Showing 16 changed files with 378 additions and 48 deletions.
5 changes: 3 additions & 2 deletions apis/apps/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,9 @@ type ClusterComponentSpec struct {
// +optional
ComponentDefRef string `json:"componentDefRef,omitempty"`

// References the name of a ComponentDefinition object.
// The ComponentDefinition specifies the behavior and characteristics of the Component.
// Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
// custom resource (CR) that defines the Component's characteristics and behavior.
//
// If both `componentDefRef` and `componentDef` are provided,
// the `componentDef` will take precedence over `componentDefRef`.
//
Expand Down
4 changes: 3 additions & 1 deletion apis/apps/v1alpha1/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,9 @@ type ClusterVars struct {

// ClusterObjectReference defines information to let you locate the referenced object inside the same Cluster.
type ClusterObjectReference struct {
// CompDef specifies the definition used by the component that the referent object resident in.
// Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
// custom resource (CR) used by the component that the referent object resident in.
//
// If not specified, the component itself will be used.
//
// +optional
Expand Down
12 changes: 8 additions & 4 deletions config/crd/bases/apps.kubeblocks.io_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,10 @@ spec:
type: object
componentDef:
description: |-
References the name of a ComponentDefinition object.
The ComponentDefinition specifies the behavior and characteristics of the Component.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) that defines the Component's characteristics and behavior.


If both `componentDefRef` and `componentDef` are provided,
the `componentDef` will take precedence over `componentDefRef`.
maxLength: 64
Expand Down Expand Up @@ -9525,8 +9527,10 @@ spec:
type: object
componentDef:
description: |-
References the name of a ComponentDefinition object.
The ComponentDefinition specifies the behavior and characteristics of the Component.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) that defines the Component's characteristics and behavior.


If both `componentDefRef` and `componentDef` are provided,
the `componentDef` will take precedence over `componentDefRef`.
maxLength: 64
Expand Down
25 changes: 20 additions & 5 deletions config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12493,7 +12493,10 @@ spec:
properties:
compDef:
description: |-
CompDef specifies the definition used by the component that the referent object resident in.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) used by the component that the referent object resident in.


If not specified, the component itself will be used.
type: string
componentName:
Expand Down Expand Up @@ -12644,7 +12647,10 @@ spec:
properties:
compDef:
description: |-
CompDef specifies the definition used by the component that the referent object resident in.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) used by the component that the referent object resident in.


If not specified, the component itself will be used.
type: string
multipleClusterObjectOption:
Expand Down Expand Up @@ -12723,7 +12729,10 @@ spec:
properties:
compDef:
description: |-
CompDef specifies the definition used by the component that the referent object resident in.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) used by the component that the referent object resident in.


If not specified, the component itself will be used.
type: string
container:
Expand Down Expand Up @@ -12832,7 +12841,10 @@ spec:
properties:
compDef:
description: |-
CompDef specifies the definition used by the component that the referent object resident in.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) used by the component that the referent object resident in.


If not specified, the component itself will be used.
type: string
endpoint:
Expand Down Expand Up @@ -12932,7 +12944,10 @@ spec:
properties:
compDef:
description: |-
CompDef specifies the definition used by the component that the referent object resident in.
Specifies the exact name, name prefix, or regular expression pattern for matching the name of the ComponentDefinition
custom resource (CR) used by the component that the referent object resident in.


If not specified, the component itself will be used.
type: string
host:
Expand Down
8 changes: 8 additions & 0 deletions controllers/apps/clusterdefinition_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ func (r *ClusterDefinitionReconciler) validateTopology(rctx intctrlutil.RequestC
return err
}
}

// validate topology reference component definitions name pattern
for _, comp := range topology.Components {
if err := component.ValidateCompDefRegexp(comp.CompDef); err != nil {
return fmt.Errorf("invalid component definition reference pattern: %s", comp.CompDef)
}
}

compDefs, err := r.loadTopologyCompDefs(rctx.Ctx, topology)
if err != nil {
return err
Expand Down
46 changes: 36 additions & 10 deletions controllers/apps/componentdefinition_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"reflect"
"strings"

"github.com/pkg/errors"
"golang.org/x/exp/slices"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -212,6 +213,38 @@ func (r *ComponentDefinitionReconciler) validateRuntime(cli client.Client, rctx

func (r *ComponentDefinitionReconciler) validateVars(cli client.Client, rctx intctrlutil.RequestCtx,
cmpd *appsv1alpha1.ComponentDefinition) error {
if !checkUniqueItemWithValue(cmpd.Spec.Vars, "Name", nil) {
return fmt.Errorf("duplicate names of component vars are not allowed")
}

// validate the reference to component definition name pattern
var compDef string
for _, cVar := range cmpd.Spec.Vars {
if cVar.ValueFrom == nil {
continue
}
switch {
case cVar.ValueFrom.HostNetworkVarRef != nil:
compDef = cVar.ValueFrom.HostNetworkVarRef.CompDef
case cVar.ValueFrom.ServiceVarRef != nil:
compDef = cVar.ValueFrom.ServiceVarRef.CompDef
case cVar.ValueFrom.ServiceRefVarRef != nil:
compDef = cVar.ValueFrom.ServiceRefVarRef.CompDef
case cVar.ValueFrom.ComponentVarRef != nil:
compDef = cVar.ValueFrom.ComponentVarRef.CompDef
case cVar.ValueFrom.CredentialVarRef != nil:
compDef = cVar.ValueFrom.CredentialVarRef.CompDef
default:
continue
}

if len(compDef) == 0 {
continue
}
if err := component.ValidateCompDefRegexp(compDef); err != nil {
return errors.Wrapf(err, "invalid reference to component definition name pattern: %s", compDef)
}
}
return nil
}

Expand Down Expand Up @@ -419,26 +452,19 @@ func listCompDefinitionsWithPattern(ctx context.Context, cli client.Reader, name
return nil, err
}
compDefsFullyMatched := make([]*appsv1alpha1.ComponentDefinition, 0)
compDefsPrefixMatched := make([]*appsv1alpha1.ComponentDefinition, 0)
compDefsRegexMatched := make([]*appsv1alpha1.ComponentDefinition, 0)
compDefsPatternMatched := make([]*appsv1alpha1.ComponentDefinition, 0)
for i, item := range compDefList.Items {
if item.Name == namePattern {
compDefsFullyMatched = append(compDefsFullyMatched, &compDefList.Items[i])
}
if strings.HasPrefix(item.Name, namePattern) {
compDefsPrefixMatched = append(compDefsPrefixMatched, &compDefList.Items[i])
}
if component.CompDefMatched(item.Name, namePattern) {
compDefsRegexMatched = append(compDefsRegexMatched, &compDefList.Items[i])
compDefsPatternMatched = append(compDefsPatternMatched, &compDefList.Items[i])
}
}
if len(compDefsFullyMatched) > 0 {
return compDefsFullyMatched, nil
}
if len(compDefsPrefixMatched) > 0 {
return compDefsPrefixMatched, nil
}
return compDefsRegexMatched, nil
return compDefsPatternMatched, nil
}

func checkUniqueItemWithValue(slice any, fieldName string, val any) bool {
Expand Down
69 changes: 69 additions & 0 deletions controllers/apps/componentdefinition_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,75 @@ var _ = Describe("ComponentDefinition Controller", func() {
})
})

Context("vars", func() {
It("ok", func() {
By("create a ComponentDefinition obj")
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
SetRuntime(nil).
AddVar(appsv1alpha1.EnvVar{
Name: "VAR1",
Value: "value1",
}).
Create(&testCtx).GetObject()

checkObjectStatus(componentDefObj, appsv1alpha1.AvailablePhase)
})

It("duplicate vars name", func() {
By("create a ComponentDefinition obj")
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
SetRuntime(nil).
AddVar(appsv1alpha1.EnvVar{
Name: "VAR1",
Value: "value1",
}).
AddVar(appsv1alpha1.EnvVar{
Name: "VAR1",
Value: "value2",
}).
Create(&testCtx).GetObject()
checkObjectStatus(componentDefObj, appsv1alpha1.UnavailablePhase)
})

It("valid var component definition name pattern", func() {
By("create a ComponentDefinition obj")
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
SetRuntime(nil).
AddVar(appsv1alpha1.EnvVar{
Name: "VAR1",
ValueFrom: &appsv1alpha1.VarSource{
ServiceRefVarRef: &appsv1alpha1.ServiceRefVarSelector{
ClusterObjectReference: appsv1alpha1.ClusterObjectReference{
Name: "service",
CompDef: "valid",
},
},
},
}).
Create(&testCtx).GetObject()
checkObjectStatus(componentDefObj, appsv1alpha1.AvailablePhase)
})

It("invalid var component definition name pattern", func() {
By("create a ComponentDefinition obj")
componentDefObj := testapps.NewComponentDefinitionFactory(componentDefName).
SetRuntime(nil).
AddVar(appsv1alpha1.EnvVar{
Name: "VAR1",
ValueFrom: &appsv1alpha1.VarSource{
ServiceVarRef: &appsv1alpha1.ServiceVarSelector{
ClusterObjectReference: appsv1alpha1.ClusterObjectReference{
Name: "service",
CompDef: "(invalid",
},
},
},
}).
Create(&testCtx).GetObject()
checkObjectStatus(componentDefObj, appsv1alpha1.UnavailablePhase)
})
})

Context("immutable", func() {
newCmpdFn := func(processor func(*testapps.MockComponentDefinitionFactory)) *appsv1alpha1.ComponentDefinition {
By("create a ComponentDefinition obj")
Expand Down
26 changes: 23 additions & 3 deletions controllers/apps/componentversion_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"slices"
"strings"

"github.com/pkg/errors"
"golang.org/x/exp/maps"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -141,6 +142,13 @@ func (r *ComponentVersionReconciler) reconcile(rctx intctrlutil.RequestCtx,
// return intctrlutil.Reconciled()
// }

if err = validateCompatibilityRulesCompDef(compVersion); err != nil {
if err1 := r.unavailable(r.Client, rctx, compVersion, err); err1 != nil {
return intctrlutil.CheckedRequeueWithError(err1, rctx.Log, "")
}
return intctrlutil.CheckedRequeueWithError(err, rctx.Log, "")
}

releaseToCompDefinitions, err := r.buildReleaseToCompDefinitionMapping(r.Client, rctx, compVersion)
if err != nil {
return intctrlutil.CheckedRequeueWithError(err, rctx.Log, "")
Expand Down Expand Up @@ -340,12 +348,24 @@ func (r *ComponentVersionReconciler) validateImages(release appsv1alpha1.Compone
return nil
}

// validateCompDef validates the reference component definition name pattern defined in compatibility rules.
func validateCompatibilityRulesCompDef(compVersion *appsv1alpha1.ComponentVersion) error {
for _, rule := range compVersion.Spec.CompatibilityRules {
for _, compDefName := range rule.CompDefs {
if err := component.ValidateCompDefRegexp(compDefName); err != nil {
return errors.Wrapf(err, "invalid reference to component definition name pattern: %s in compatibility rules", compDefName)
}
}
}
return nil
}

// resolveCompDefinitionNServiceVersion resolves and returns the specific component definition object and the service version supported.
func resolveCompDefinitionNServiceVersion(ctx context.Context, cli client.Reader, compDefName, serviceVersion string) (*appsv1alpha1.ComponentDefinition, string, error) {
func resolveCompDefinitionNServiceVersion(ctx context.Context, cli client.Reader, compDefNamePattern, serviceVersion string) (*appsv1alpha1.ComponentDefinition, string, error) {
var (
compDef *appsv1alpha1.ComponentDefinition
)
compDefs, err := listCompDefinitionsWithPattern(ctx, cli, compDefName)
compDefs, err := listCompDefinitionsWithPattern(ctx, cli, compDefNamePattern)
if err != nil {
return compDef, serviceVersion, err
}
Expand All @@ -368,7 +388,7 @@ func resolveCompDefinitionNServiceVersion(ctx context.Context, cli client.Reader
// component definitions that support the service version
compatibleCompDefs := serviceVersionToCompDefs[serviceVersion]
if len(compatibleCompDefs) == 0 {
return compDef, serviceVersion, fmt.Errorf("no matched component definition found: %s", compDefName)
return compDef, serviceVersion, fmt.Errorf("no matched component definition found: %s", compDefNamePattern)
}

// choose the latest one
Expand Down
Loading

0 comments on commit 21ef324

Please sign in to comment.