diff --git a/controllers/apps/clusterdefinition_controller_test.go b/controllers/apps/clusterdefinition_controller_test.go
index 241bed304da..f5698ea48ef 100644
--- a/controllers/apps/clusterdefinition_controller_test.go
+++ b/controllers/apps/clusterdefinition_controller_test.go
@@ -58,7 +58,6 @@ var _ = Describe("ClusterDefinition Controller", func() {
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ClusterDefinitionSignature, true, ml)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ShardingDefinitionSignature, true, ml)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ComponentDefinitionSignature, true, ml)
- testapps.ClearResources(&testCtx, intctrlutil.ConfigConstraintSignature, ml)
// namespaced
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ConfigMapSignature, true, inNS, ml)
diff --git a/controllers/apps/component_controller.go b/controllers/apps/component_controller.go
index a2bd75a6ae2..f1a186541ba 100644
--- a/controllers/apps/component_controller.go
+++ b/controllers/apps/component_controller.go
@@ -37,7 +37,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
@@ -152,14 +151,12 @@ func (r *ComponentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
&componentAccountTransformer{},
// handle the TLS configuration
&componentTLSTransformer{Client: r.Client},
- // rerender parameters after v-scale and h-scale
- &componentRelatedParametersTransformer{Client: r.Client},
// resolve and build vars for template and Env
&componentVarsTransformer{},
// provision component system accounts, depend on vars
&componentAccountProvisionTransformer{},
// render component configurations
- &componentConfigurationTransformer{Client: r.Client},
+ &componentReloadActionSidecarTransformer{Client: r.Client},
// handle restore before workloads transform
&componentRestoreTransformer{Client: r.Client},
// handle the component workload
@@ -207,8 +204,7 @@ func (r *ComponentReconciler) setupWithManager(mgr ctrl.Manager) error {
Owns(&corev1.Secret{}).
Owns(&corev1.ConfigMap{}).
Watches(&dpv1alpha1.Restore{}, handler.EnqueueRequestsFromMapFunc(r.filterComponentResources)).
- Watches(&corev1.PersistentVolumeClaim{}, handler.EnqueueRequestsFromMapFunc(r.filterComponentResources)).
- Watches(&appsv1alpha1.Configuration{}, handler.EnqueueRequestsFromMapFunc(r.configurationEventHandler))
+ Watches(&corev1.PersistentVolumeClaim{}, handler.EnqueueRequestsFromMapFunc(r.filterComponentResources))
if viper.GetBool(constant.EnableRBACManager) {
b.Owns(&rbacv1.RoleBinding{}).
@@ -228,8 +224,7 @@ func (r *ComponentReconciler) setupWithMultiClusterManager(mgr ctrl.Manager, mul
MaxConcurrentReconciles: viper.GetInt(constant.CfgKBReconcileWorkers),
}).
Owns(&workloads.InstanceSet{}).
- Watches(&dpv1alpha1.Restore{}, handler.EnqueueRequestsFromMapFunc(r.filterComponentResources)).
- Watches(&appsv1alpha1.Configuration{}, handler.EnqueueRequestsFromMapFunc(r.configurationEventHandler))
+ Watches(&dpv1alpha1.Restore{}, handler.EnqueueRequestsFromMapFunc(r.filterComponentResources))
eventHandler := handler.EnqueueRequestsFromMapFunc(r.filterComponentResources)
multiClusterMgr.Watch(b, &corev1.Service{}, eventHandler).
@@ -263,18 +258,3 @@ func (r *ComponentReconciler) filterComponentResources(ctx context.Context, obj
},
}
}
-
-func (r *ComponentReconciler) configurationEventHandler(_ context.Context, obj client.Object) []reconcile.Request {
- cr, ok := obj.(*appsv1alpha1.Configuration)
- if !ok {
- return []reconcile.Request{}
- }
- return []reconcile.Request{
- {
- NamespacedName: types.NamespacedName{
- Namespace: obj.GetNamespace(),
- Name: constant.GenerateClusterComponentName(cr.Spec.ClusterRef, cr.Spec.ComponentName),
- },
- },
- }
-}
diff --git a/controllers/apps/componentdefinition_controller_test.go b/controllers/apps/componentdefinition_controller_test.go
index 204a50169e0..d218dd60dd9 100644
--- a/controllers/apps/componentdefinition_controller_test.go
+++ b/controllers/apps/componentdefinition_controller_test.go
@@ -61,7 +61,6 @@ var _ = Describe("ComponentDefinition Controller", func() {
// non-namespaced
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ComponentDefinitionSignature, true, ml)
- testapps.ClearResources(&testCtx, intctrlutil.ConfigConstraintSignature, ml)
// namespaced
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.ConfigMapSignature, true, inNS, ml)
diff --git a/controllers/apps/suite_test.go b/controllers/apps/suite_test.go
index 21a4145781b..c42df5a778f 100644
--- a/controllers/apps/suite_test.go
+++ b/controllers/apps/suite_test.go
@@ -43,8 +43,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
- appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
opsv1alpha1 "github.com/apecloud/kubeblocks/apis/operations/v1alpha1"
parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
@@ -123,18 +121,10 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
- err = appsv1alpha1.AddToScheme(scheme.Scheme)
- Expect(err).NotTo(HaveOccurred())
- model.AddScheme(appsv1alpha1.AddToScheme)
-
err = opsv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
model.AddScheme(opsv1alpha1.AddToScheme)
- err = appsv1beta1.AddToScheme(scheme.Scheme)
- Expect(err).NotTo(HaveOccurred())
- model.AddScheme(appsv1beta1.AddToScheme)
-
err = appsv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
model.AddScheme(appsv1.AddToScheme)
@@ -255,6 +245,13 @@ var _ = BeforeSuite(func() {
}).SetupWithManager(k8sManager, nil)
Expect(err).ToNot(HaveOccurred())
+ err = (¶meters.ComponentDrivenParameterReconciler{
+ Client: k8sManager.GetClient(),
+ Scheme: k8sManager.GetScheme(),
+ Recorder: k8sManager.GetEventRecorderFor("component-parameter-controller"),
+ }).SetupWithManager(k8sManager)
+ Expect(err).ToNot(HaveOccurred())
+
err = (¶meters.ParametersDefinitionReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
diff --git a/controllers/apps/transformer_component_configuration.go b/controllers/apps/transformer_component_configuration.go
deleted file mode 100644
index 0cc0a8afd52..00000000000
--- a/controllers/apps/transformer_component_configuration.go
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package apps
-
-import (
- corev1 "k8s.io/api/core/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- "github.com/apecloud/kubeblocks/pkg/common"
- "github.com/apecloud/kubeblocks/pkg/controller/graph"
- "github.com/apecloud/kubeblocks/pkg/controller/model"
- "github.com/apecloud/kubeblocks/pkg/controller/plan"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
-)
-
-// componentConfigurationTransformer handles component configuration render
-type componentConfigurationTransformer struct {
- client.Client
-}
-
-var _ graph.Transformer = &componentConfigurationTransformer{}
-
-func (t *componentConfigurationTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error {
- transCtx, _ := ctx.(*componentTransformContext)
-
- comp := transCtx.Component
- cluster := transCtx.Cluster
- compOrig := transCtx.ComponentOrig
- synthesizeComp := transCtx.SynthesizeComponent
-
- if model.IsObjectDeleting(compOrig) {
- return nil
- }
- if common.IsCompactMode(compOrig.Annotations) {
- transCtx.V(1).Info("Component is in compact mode, no need to create configuration related objects",
- "component", client.ObjectKeyFromObject(transCtx.ComponentOrig))
- return nil
- }
-
- // get dependOnObjs which will be used in configuration render
- var dependOnObjs []client.Object
- for _, vertex := range dag.Vertices() {
- v, _ := vertex.(*model.ObjectVertex)
- if cm, ok := v.Obj.(*corev1.ConfigMap); ok {
- dependOnObjs = append(dependOnObjs, cm)
- continue
- }
- if secret, ok := v.Obj.(*corev1.Secret); ok {
- dependOnObjs = append(dependOnObjs, secret)
- continue
- }
- }
-
- // configuration render
- if err := plan.RenderConfigNScriptFiles(
- &render.ResourceCtx{
- Context: transCtx.Context,
- Client: t.Client,
- Namespace: comp.GetNamespace(),
- ClusterName: synthesizeComp.ClusterName,
- ComponentName: synthesizeComp.Name,
- },
- cluster,
- comp,
- synthesizeComp,
- synthesizeComp.PodSpec,
- dependOnObjs); err != nil {
- return err
- }
- return nil
-}
diff --git a/controllers/apps/transformer_component_deletion.go b/controllers/apps/transformer_component_deletion.go
index fe7e58beff3..5f7dbbcca7f 100644
--- a/controllers/apps/transformer_component_deletion.go
+++ b/controllers/apps/transformer_component_deletion.go
@@ -30,7 +30,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/component"
@@ -169,7 +169,7 @@ func compOwnedKinds() []client.ObjectList {
&corev1.SecretList{},
&corev1.ConfigMapList{},
&corev1.PersistentVolumeClaimList{},
- &appsv1alpha1.ConfigurationList{},
+ ¶metersv1alpha1.ComponentParameterList{},
&corev1.ServiceAccountList{},
&rbacv1.RoleBindingList{},
}
diff --git a/controllers/apps/transformer_component_parameters.go b/controllers/apps/transformer_component_parameters.go
deleted file mode 100644
index d34ebbd7f8b..00000000000
--- a/controllers/apps/transformer_component_parameters.go
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package apps
-
-import (
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
- "github.com/apecloud/kubeblocks/pkg/controller/configuration"
- "github.com/apecloud/kubeblocks/pkg/controller/graph"
- intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
-)
-
-type componentRelatedParametersTransformer struct {
- client.Client
-}
-
-var _ = componentRelatedParametersTransformer{}
-
-func (c *componentRelatedParametersTransformer) Transform(ctx graph.TransformContext, _ *graph.DAG) error {
- transCtx, _ := ctx.(*componentTransformContext)
- synthesizedComp := transCtx.SynthesizeComponent
-
- componentParameter := ¶metersv1alpha1.ComponentParameter{}
- configKey := client.ObjectKey{Namespace: synthesizedComp.Namespace,
- Name: cfgcore.GenerateComponentConfigurationName(synthesizedComp.ClusterName, synthesizedComp.Name)}
- if err := c.Get(ctx.GetContext(), configKey, componentParameter); err != nil {
- return client.IgnoreNotFound(err)
- }
-
- configRender, err := intctrlutil.ResolveComponentConfigRender(ctx.GetContext(), c, transCtx.CompDef)
- if err != nil {
- return client.IgnoreNotFound(err)
- }
- if configRender == nil {
- return nil
- }
-
- configNew := componentParameter.DeepCopy()
- if err = configuration.UpdateConfigPayload(&configNew.Spec, &transCtx.Component.Spec, &configRender.Spec); err != nil {
- return err
- }
- return c.Patch(ctx.GetContext(), configNew, client.MergeFrom(componentParameter.DeepCopy()))
-}
diff --git a/controllers/apps/transformer_component_reconfigure.go b/controllers/apps/transformer_component_reconfigure.go
new file mode 100644
index 00000000000..1da13e500b6
--- /dev/null
+++ b/controllers/apps/transformer_component_reconfigure.go
@@ -0,0 +1,142 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+This file is part of KubeBlocks project
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+
+package apps
+
+import (
+ "context"
+
+ corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
+ "github.com/apecloud/kubeblocks/pkg/common"
+ "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/controller/component"
+ configctrl "github.com/apecloud/kubeblocks/pkg/controller/configuration"
+ "github.com/apecloud/kubeblocks/pkg/controller/graph"
+ "github.com/apecloud/kubeblocks/pkg/controller/model"
+ "github.com/apecloud/kubeblocks/pkg/controller/render"
+ intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
+)
+
+// componentReloadActionSidecarTransformer handles component configuration render
+type componentReloadActionSidecarTransformer struct {
+ client.Client
+}
+
+var _ graph.Transformer = &componentReloadActionSidecarTransformer{}
+
+func (t *componentReloadActionSidecarTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error {
+ transCtx, _ := ctx.(*componentTransformContext)
+
+ comp := transCtx.Component
+ cluster := transCtx.Cluster
+ compOrig := transCtx.ComponentOrig
+ synthesizeComp := transCtx.SynthesizeComponent
+
+ if model.IsObjectDeleting(compOrig) {
+ return nil
+ }
+ if common.IsCompactMode(compOrig.Annotations) {
+ transCtx.V(1).Info("Component is in compact mode, no need to create configuration related objects",
+ "component", client.ObjectKeyFromObject(transCtx.ComponentOrig))
+ return nil
+ }
+
+ reconcileCtx := &render.ResourceCtx{
+ Context: transCtx.Context,
+ Client: t.Client,
+ Namespace: comp.GetNamespace(),
+ ClusterName: synthesizeComp.ClusterName,
+ ComponentName: synthesizeComp.Name,
+ }
+
+ var configmaps []*corev1.ConfigMap
+ cachedObjs := resolveRerenderDependOnObjects(dag)
+ for _, tpls := range [][]appsv1.ComponentTemplateSpec{synthesizeComp.ScriptTemplates, synthesizeComp.ConfigTemplates} {
+ objects, err := render.RenderTemplate(reconcileCtx, cluster, synthesizeComp, comp, cachedObjs, tpls)
+ if err != nil {
+ return err
+ }
+ configmaps = append(configmaps, objects...)
+ }
+
+ graphCli, _ := transCtx.Client.(model.GraphClient)
+ if err := ensureConfigMapsPresence(transCtx, graphCli, dag, configmaps...); err != nil {
+ return err
+ }
+ if err := updatePodVolumes(synthesizeComp.PodSpec, synthesizeComp); err != nil {
+ return err
+ }
+ if len(synthesizeComp.ConfigTemplates) == 0 {
+ return nil
+ }
+
+ return configctrl.BuildReloadActionContainer(reconcileCtx, cluster, synthesizeComp, transCtx.CompDef, configmaps)
+}
+
+func ensureConfigMapsPresence(ctx context.Context, cli model.GraphClient, dag *graph.DAG, configmaps ...*corev1.ConfigMap) error {
+ for _, configmap := range configmaps {
+ var cm = &corev1.ConfigMap{}
+ if err := cli.Get(ctx, client.ObjectKeyFromObject(configmap), cm); err != nil {
+ if !apierrors.IsNotFound(err) {
+ return err
+ }
+ cli.Create(dag, configmap, inDataContext4G())
+ }
+ }
+ return nil
+}
+
+func resolveRerenderDependOnObjects(dag *graph.DAG) []client.Object {
+ var dependOnObjs []client.Object
+ for _, vertex := range dag.Vertices() {
+ v, _ := vertex.(*model.ObjectVertex)
+ if cm, ok := v.Obj.(*corev1.ConfigMap); ok {
+ dependOnObjs = append(dependOnObjs, cm)
+ continue
+ }
+ if secret, ok := v.Obj.(*corev1.Secret); ok {
+ dependOnObjs = append(dependOnObjs, secret)
+ continue
+ }
+ }
+ return dependOnObjs
+}
+
+func updatePodVolumes(podSpec *corev1.PodSpec, component *component.SynthesizedComponent) error {
+ volumes := make(map[string]appsv1.ComponentTemplateSpec, len(component.ConfigTemplates))
+ for _, tpls := range [][]appsv1.ComponentTemplateSpec{component.ConfigTemplates, component.ScriptTemplates} {
+ for _, tpl := range tpls {
+ cmName := core.GetComponentCfgName(component.ClusterName, component.Name, tpl.Name)
+ volumes[cmName] = tpl
+ }
+ }
+ return intctrlutil.CreateOrUpdatePodVolumes(podSpec, volumes, configSetsFromComponent(component.ConfigTemplates))
+}
+
+func configSetsFromComponent(templates []appsv1.ComponentTemplateSpec) []string {
+ configSet := make([]string, 0, len(templates))
+ for _, template := range templates {
+ configSet = append(configSet, template.Name)
+ }
+ return configSet
+}
diff --git a/controllers/apps/transformer_component_status.go b/controllers/apps/transformer_component_status.go
index 5fc3e5c65b3..8d7b45e6da0 100644
--- a/controllers/apps/transformer_component_status.go
+++ b/controllers/apps/transformer_component_status.go
@@ -34,15 +34,12 @@ import (
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
- cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/apecloud/kubeblocks/pkg/controller/graph"
"github.com/apecloud/kubeblocks/pkg/controller/instanceset"
"github.com/apecloud/kubeblocks/pkg/controller/model"
- intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
)
const (
@@ -133,12 +130,6 @@ func (t *componentStatusTransformer) reconcileStatus(transCtx *componentTransfor
// check if the ITS is running
isITSUpdatedNRunning := t.isInstanceSetRunning()
- // check if all configTemplates are synced
- isAllConfigSynced, err := t.isAllConfigSynced(transCtx)
- if err != nil {
- return err
- }
-
// check if the component has failed pod
hasFailedPod, messages := t.hasFailedPod()
@@ -175,8 +166,8 @@ func (t *componentStatusTransformer) reconcileStatus(transCtx *componentTransfor
}()
transCtx.Logger.Info(
- fmt.Sprintf("status conditions, creating: %v, its running: %v, has failure: %v, updating: %v, config synced: %v",
- isInCreatingPhase, isITSUpdatedNRunning, hasFailure, hasRunningScaleOut || hasRunningVolumeExpansion, isAllConfigSynced))
+ fmt.Sprintf("status conditions, creating: %v, its running: %v, has failure: %v, updating: %v",
+ isInCreatingPhase, isITSUpdatedNRunning, hasFailure, hasRunningScaleOut || hasRunningVolumeExpansion))
switch {
case isDeleting:
@@ -185,7 +176,7 @@ func (t *componentStatusTransformer) reconcileStatus(transCtx *componentTransfor
t.setComponentStatusPhase(transCtx, appsv1.StoppingComponentPhase, nil, "component is Stopping")
case stopped:
t.setComponentStatusPhase(transCtx, appsv1.StoppedComponentPhase, nil, "component is Stopped")
- case isITSUpdatedNRunning && isAllConfigSynced && !hasRunningScaleOut && !hasRunningVolumeExpansion:
+ case isITSUpdatedNRunning && !hasRunningScaleOut && !hasRunningVolumeExpansion:
t.setComponentStatusPhase(transCtx, appsv1.RunningComponentPhase, nil, "component is Running")
case !hasFailure && isInCreatingPhase:
t.setComponentStatusPhase(transCtx, appsv1.CreatingComponentPhase, nil, "component is Creating")
@@ -234,46 +225,6 @@ func (t *componentStatusTransformer) isInstanceSetRunning() bool {
return instanceset.IsInstanceSetReady(t.runningITS)
}
-// isAllConfigSynced checks if all configTemplates are synced.
-func (t *componentStatusTransformer) isAllConfigSynced(transCtx *componentTransformContext) (bool, error) {
- var (
- cmKey client.ObjectKey
- cmObj = &corev1.ConfigMap{}
- )
-
- if len(t.synthesizeComp.ConfigTemplates) == 0 {
- return true, nil
- }
-
- configurationKey := client.ObjectKey{
- Namespace: t.cluster.Namespace,
- Name: cfgcore.GenerateComponentConfigurationName(t.cluster.Name, t.synthesizeComp.Name),
- }
- configuration := ¶metersv1alpha1.ComponentParameter{}
- if err := t.Client.Get(transCtx.Context, configurationKey, configuration); err != nil {
- return false, err
- }
- for _, configSpec := range t.synthesizeComp.ConfigTemplates {
- item := intctrlutil.GetConfigTemplateItem(&configuration.Spec, configSpec.Name)
- status := intctrlutil.GetItemStatus(&configuration.Status, configSpec.Name)
- // for creating phase
- if item == nil || status == nil {
- return false, nil
- }
- cmKey = client.ObjectKey{
- Namespace: t.cluster.Namespace,
- Name: cfgcore.GetComponentCfgName(t.cluster.Name, t.synthesizeComp.Name, configSpec.Name),
- }
- if err := t.Client.Get(transCtx.Context, cmKey, cmObj, inDataContext4C()); err != nil {
- return false, err
- }
- if intctrlutil.GetConfigSpecReconcilePhase(cmObj, *item, status) != parametersv1alpha1.CFinishedPhase {
- return false, nil
- }
- }
- return true, nil
-}
-
// hasScaleOutRunning checks if the scale out is running.
func (t *componentStatusTransformer) hasScaleOutRunning(transCtx *componentTransformContext) (running bool, failed bool, err error) {
if t.runningITS == nil || t.runningITS.Spec.Replicas == nil {
diff --git a/controllers/parameters/componentdrivenparameter_controller.go b/controllers/parameters/componentdrivenparameter_controller.go
new file mode 100644
index 00000000000..83209bf4213
--- /dev/null
+++ b/controllers/parameters/componentdrivenparameter_controller.go
@@ -0,0 +1,235 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+This file is part of KubeBlocks project
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+
+package parameters
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/tools/record"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+
+ appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
+ configcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/constant"
+ "github.com/apecloud/kubeblocks/pkg/controller/builder"
+ "github.com/apecloud/kubeblocks/pkg/controller/component"
+ configctrl "github.com/apecloud/kubeblocks/pkg/controller/configuration"
+ "github.com/apecloud/kubeblocks/pkg/controller/model"
+ intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
+)
+
+// ComponentDrivenParameterReconciler reconciles a Parameter object
+type ComponentDrivenParameterReconciler struct {
+ client.Client
+ Scheme *runtime.Scheme
+ Recorder record.EventRecorder
+}
+
+// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=components,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=components/status,verbs=get;update;patch
+// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=components/finalizers,verbs=update
+
+// +kubebuilder:rbac:groups=parameters.kubeblocks.io,resources=componentparameters,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=parameters.kubeblocks.io,resources=componentparameters/status,verbs=get;update;patch
+// +kubebuilder:rbac:groups=parameters.kubeblocks.io,resources=componentparameters/finalizers,verbs=update
+
+// Reconcile is part of the main kubernetes reconciliation loop which aims to
+// move the current state of the cluster closer to the desired state.
+//
+// For more details, check Reconcile and its Result here:
+// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile
+func (r *ComponentDrivenParameterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ reqCtx := intctrlutil.RequestCtx{
+ Ctx: ctx,
+ Req: req,
+ Recorder: r.Recorder,
+ Log: log.FromContext(ctx).
+ WithName("ComponentParameterReconciler").
+ WithValues("Namespace", req.Namespace, "Parameter", req.Name),
+ }
+
+ comp := &appsv1.Component{}
+ if err := r.Client.Get(reqCtx.Ctx, reqCtx.Req.NamespacedName, comp); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+ return r.reconcile(reqCtx, comp)
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *ComponentDrivenParameterReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewControllerManagedBy(mgr).
+ For(&appsv1.Component{}).
+ Complete(r)
+}
+
+func (r *ComponentDrivenParameterReconciler) reconcile(reqCtx intctrlutil.RequestCtx, component *appsv1.Component) (ctrl.Result, error) {
+ var err error
+ var existingObject *parametersv1alpha1.ComponentParameter
+ var expectedObject *parametersv1alpha1.ComponentParameter
+
+ if existingObject, err = runningComponentParameter(reqCtx, r.Client, component); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+ if model.IsObjectDeleting(component) {
+ return r.delete(reqCtx, existingObject)
+ }
+ if expectedObject, err = buildComponentParameter(reqCtx, r.Client, component); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+
+ switch {
+ case expectedObject == nil:
+ return r.delete(reqCtx, existingObject)
+ case existingObject == nil:
+ return r.create(reqCtx, expectedObject)
+ default:
+ return r.update(reqCtx, expectedObject, existingObject)
+ }
+}
+
+func (r *ComponentDrivenParameterReconciler) create(reqCtx intctrlutil.RequestCtx, object *parametersv1alpha1.ComponentParameter) (ctrl.Result, error) {
+ if err := r.Client.Create(reqCtx.Ctx, object); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+ reqCtx.Log.Info("ComponentParameter created")
+ intctrlutil.RecordCreatedEvent(r.Recorder, object)
+ return intctrlutil.Reconciled()
+}
+
+func (r *ComponentDrivenParameterReconciler) delete(reqCtx intctrlutil.RequestCtx, object *parametersv1alpha1.ComponentParameter) (ctrl.Result, error) {
+ if object == nil {
+ return intctrlutil.Reconciled()
+ }
+ if err := r.Client.Delete(reqCtx.Ctx, object); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+ reqCtx.Log.Info("ComponentParameter deleted")
+ return intctrlutil.Reconciled()
+}
+
+func (r *ComponentDrivenParameterReconciler) update(reqCtx intctrlutil.RequestCtx, expected, existing *parametersv1alpha1.ComponentParameter) (ctrl.Result, error) {
+ mergedObject := r.mergeComponentParameter(expected, existing)
+ if reflect.DeepEqual(mergedObject, existing) {
+ return intctrlutil.Reconciled()
+ }
+ if err := r.Client.Patch(reqCtx.Ctx, mergedObject, client.MergeFrom(existing)); err != nil {
+ return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "")
+ }
+ return intctrlutil.Reconciled()
+}
+
+func runningComponentParameter(reqCtx intctrlutil.RequestCtx, reader client.Reader, comp *appsv1.Component) (*parametersv1alpha1.ComponentParameter, error) {
+ var componentParameter = ¶metersv1alpha1.ComponentParameter{}
+
+ clusterName, _ := component.GetClusterName(comp)
+ componentName, _ := component.ShortName(clusterName, comp.Name)
+
+ parameterKey := types.NamespacedName{
+ Name: configcore.GenerateComponentConfigurationName(clusterName, componentName),
+ Namespace: comp.Namespace,
+ }
+ if err := reader.Get(reqCtx.Ctx, parameterKey, componentParameter); err != nil {
+ return nil, client.IgnoreNotFound(err)
+ }
+ return componentParameter, nil
+}
+
+func getCompDefinition(ctx context.Context, cli client.Reader, comp *appsv1.Component) (*appsv1.ComponentDefinition, error) {
+ compKey := types.NamespacedName{
+ Name: comp.Spec.CompDef,
+ }
+ cmpd := &appsv1.ComponentDefinition{}
+ if err := cli.Get(ctx, compKey, cmpd); err != nil {
+ return nil, err
+ }
+ if cmpd.Status.Phase != appsv1.AvailablePhase {
+ return nil, fmt.Errorf("the referenced ComponentDefinition is unavailable: %s", cmpd.Name)
+ }
+ return cmpd, nil
+}
+
+func buildComponentParameter(reqCtx intctrlutil.RequestCtx, reader client.Reader, comp *appsv1.Component) (*parametersv1alpha1.ComponentParameter, error) {
+ var err error
+ var cmpd *appsv1.ComponentDefinition
+
+ if cmpd, err = getCompDefinition(reqCtx.Ctx, reader, comp); err != nil {
+ return nil, err
+ }
+ if len(cmpd.Spec.Configs) == 0 {
+ return nil, nil
+ }
+
+ configRender, paramsDefs, err := intctrlutil.ResolveCmpdParametersDefs(reqCtx.Ctx, reader, cmpd)
+ if err != nil {
+ return nil, err
+ }
+ tpls, err := resolveComponentTemplate(reqCtx.Ctx, reader, cmpd)
+ if err != nil {
+ return nil, err
+ }
+
+ clusterName, _ := component.GetClusterName(comp)
+ componentName, _ := component.ShortName(clusterName, comp.Name)
+ parameterObj := builder.NewComponentParameterBuilder(comp.Namespace,
+ configcore.GenerateComponentConfigurationName(clusterName, componentName)).
+ AddLabelsInMap(constant.GetCompLabelsWithDef(clusterName, componentName, cmpd.Name)).
+ ClusterRef(clusterName).
+ Component(componentName).
+ SetConfigurationItem(configctrl.ClassifyParamsFromConfigTemplate(
+ intctrlutil.TransformComponentParameters(comp.Spec.InitParameters),
+ cmpd, paramsDefs, tpls)).
+ GetObject()
+ if err = intctrlutil.SetOwnerReference(comp, parameterObj); err != nil {
+ return nil, err
+ }
+ if configRender != nil {
+ err = configctrl.UpdateConfigPayload(¶meterObj.Spec, &comp.Spec, &configRender.Spec)
+ }
+ return parameterObj, err
+}
+
+func resolveComponentTemplate(ctx context.Context, reader client.Reader, cmpd *appsv1.ComponentDefinition) (map[string]*corev1.ConfigMap, error) {
+ tpls := make(map[string]*corev1.ConfigMap, len(cmpd.Spec.Configs))
+ for _, config := range cmpd.Spec.Configs {
+ cm := &corev1.ConfigMap{}
+ if err := reader.Get(ctx, client.ObjectKey{Name: config.TemplateRef, Namespace: config.Namespace}, cm); err != nil {
+ return nil, err
+ }
+ tpls[config.Name] = cm
+ }
+ return tpls, nil
+}
+
+func (r *ComponentDrivenParameterReconciler) mergeComponentParameter(expected *parametersv1alpha1.ComponentParameter, existing *parametersv1alpha1.ComponentParameter) *parametersv1alpha1.ComponentParameter {
+ return configctrl.MergeComponentParameter(expected, existing, func(dest, expected *parametersv1alpha1.ConfigTemplateItemDetail) {
+ if len(dest.ConfigFileParams) == 0 && len(expected.ConfigFileParams) != 0 {
+ dest.ConfigFileParams = expected.ConfigFileParams
+ }
+ dest.Payload = expected.Payload
+ })
+}
diff --git a/controllers/parameters/componentdrivenparameter_controller_test.go b/controllers/parameters/componentdrivenparameter_controller_test.go
new file mode 100644
index 00000000000..18de079ec8a
--- /dev/null
+++ b/controllers/parameters/componentdrivenparameter_controller_test.go
@@ -0,0 +1,111 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+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 parameters
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
+ "k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
+ configcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/constant"
+ intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
+ testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
+ testparameters "github.com/apecloud/kubeblocks/pkg/testutil/parameters"
+)
+
+var _ = Describe("ComponentParameterGenerator Controller", func() {
+
+ BeforeEach(cleanEnv)
+
+ AfterEach(cleanEnv)
+
+ initTestResource := func() *appsv1.Component {
+ By("Create a config template obj")
+ configmap := testparameters.NewComponentTemplateFactory(configSpecName, testCtx.DefaultNamespace).
+ Create(&testCtx).
+ GetObject()
+
+ By("Create a parameters definition obj")
+ paramsDef := testparameters.NewParametersDefinitionFactory(paramsDefName).
+ SetReloadAction(testparameters.WithNoneAction()).
+ Create(&testCtx).
+ GetObject()
+ Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(paramsDef), func(obj *parametersv1alpha1.ParametersDefinition) {
+ obj.Status.Phase = parametersv1alpha1.PDAvailablePhase
+ })()).Should(Succeed())
+
+ By("Create a component definition obj and mock to available")
+ compDefObj := testapps.NewComponentDefinitionFactory(compDefName).
+ WithRandomName().
+ SetDefaultSpec().
+ AddConfigTemplate(configSpecName, configmap.Name, testCtx.DefaultNamespace, configVolumeName).
+ Create(&testCtx).
+ GetObject()
+ Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(compDefObj), func(obj *appsv1.ComponentDefinition) {
+ obj.Status.Phase = appsv1.AvailablePhase
+ })()).Should(Succeed())
+
+ pdcr := testparameters.NewParametersDrivenConfigFactory(pdcrName).
+ SetParametersDefs(paramsDef.Name).
+ SetComponentDefinition(compDefObj.GetName()).
+ SetTemplateName(configSpecName).
+ HScaleEnabled().
+ VScaleEnabled().
+ TLSEnabled().
+ Create(&testCtx).
+ GetObject()
+ Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(pdcr), func(obj *parametersv1alpha1.ParameterDrivenConfigRender) {
+ obj.Status.Phase = parametersv1alpha1.PDAvailablePhase
+ })()).Should(Succeed())
+
+ By("Create a component obj")
+ fullCompName := constant.GenerateClusterComponentName(clusterName, defaultCompName)
+ compObj := testapps.NewComponentFactory(testCtx.DefaultNamespace, fullCompName, compDefObj.Name).
+ AddLabels(constant.AppInstanceLabelKey, clusterName).
+ SetUID(types.UID("test-uid")).
+ SetReplicas(1).
+ SetResources(corev1.ResourceRequirements{Limits: corev1.ResourceList{"memory": resource.MustParse("2Gi")}}).
+ Create(&testCtx).
+ GetObject()
+
+ return compObj
+ }
+
+ Context("Generate ComponentParameter", func() {
+ It("Should reconcile success", func() {
+ component := initTestResource()
+ parameterKey := types.NamespacedName{
+ Namespace: component.Namespace,
+ Name: configcore.GenerateComponentConfigurationName(clusterName, defaultCompName),
+ }
+
+ Eventually(testapps.CheckObj(&testCtx, parameterKey, func(g Gomega, parameter *parametersv1alpha1.ComponentParameter) {
+ item := intctrlutil.GetConfigTemplateItem(¶meter.Spec, configSpecName)
+ g.Expect(item).ShouldNot(BeNil())
+ g.Expect(item.Payload).Should(HaveKey(constant.ReplicasPayload))
+ g.Expect(item.Payload).Should(HaveKey(constant.ComponentResourcePayload))
+ })).Should(Succeed())
+ })
+ })
+})
diff --git a/controllers/parameters/configuration_test.go b/controllers/parameters/configuration_test.go
index 9a0274466e7..06e0dc14bba 100644
--- a/controllers/parameters/configuration_test.go
+++ b/controllers/parameters/configuration_test.go
@@ -179,7 +179,6 @@ func cleanEnv() {
inNS := client.InNamespace(testCtx.DefaultNamespace)
ml := client.HasLabels{testCtx.TestObjLabelKey}
// non-namespaced
- testapps.ClearResources(&testCtx, generics.ConfigConstraintSignature, ml)
testapps.ClearResources(&testCtx, generics.ParametersDefinitionSignature, ml)
testapps.ClearResources(&testCtx, generics.ParameterDrivenConfigRenderSignature, ml)
// namespaced
@@ -187,7 +186,6 @@ func cleanEnv() {
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ConfigMapSignature, true, inNS)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.SecretSignature, true, inNS)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.InstanceSetSignature, true, inNS, ml)
- testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ConfigurationSignature, false, inNS, ml)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ComponentParameterSignature, true, inNS)
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ParameterSignature, true, inNS, ml)
}
diff --git a/controllers/parameters/reconcile_task.go b/controllers/parameters/reconcile_task.go
index 2b352c15197..161158e1dd4 100644
--- a/controllers/parameters/reconcile_task.go
+++ b/controllers/parameters/reconcile_task.go
@@ -21,16 +21,25 @@ package parameters
import (
"context"
+ "encoding/json"
+ "errors"
+ "reflect"
"strconv"
corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
"github.com/apecloud/kubeblocks/pkg/configuration/core"
cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util"
+ "github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/component"
configctrl "github.com/apecloud/kubeblocks/pkg/controller/configuration"
+ "github.com/apecloud/kubeblocks/pkg/controller/model"
"github.com/apecloud/kubeblocks/pkg/controller/render"
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
)
@@ -132,32 +141,190 @@ func syncImpl(taskCtx *TaskContext,
status *parametersv1alpha1.ConfigTemplateItemDetailStatus,
revision string,
configMap *corev1.ConfigMap) (err error) {
- err = configctrl.NewReconcilePipeline(render.ReconcileCtx{
- ResourceCtx: fromResourceCtx(fetcher.ResourceCtx),
+ if intctrlutil.IsApplyConfigChanged(configMap, item) {
+ return nil
+ }
+
+ failStatus := func(err error) error {
+ status.Message = pointer.String(err.Error())
+ status.Phase = parametersv1alpha1.CMergeFailedPhase
+ return err
+ }
+
+ reconcileCtx := &render.ReconcileCtx{
+ ResourceCtx: fetcher.ResourceCtx,
Cluster: fetcher.ClusterObj,
Component: fetcher.ComponentObj,
SynthesizedComponent: taskCtx.component,
PodSpec: taskCtx.component.PodSpec,
- }, item, status, configMap, taskCtx.componentParameter).
- ComponentAndComponentDef().
- PrepareForTemplate().
- RerenderTemplate().
- ApplyParameters().
- UpdateConfigVersion(revision).
- Sync().
- Complete()
+ }
- if err != nil {
- status.Message = cfgutil.ToPointer(err.Error())
- status.Phase = parametersv1alpha1.CMergeFailedPhase
- } else {
- status.Message = nil
- status.Phase = parametersv1alpha1.CMergedPhase
+ var baseConfig = configMap
+ var updatedConfig *corev1.ConfigMap
+ if intctrlutil.IsRerender(configMap, item) {
+ if baseConfig, err = configctrl.RerenderParametersTemplate(reconcileCtx, item, taskCtx.configRender, taskCtx.paramsDefs); err != nil {
+ return failStatus(err)
+ }
+ updatedConfig = baseConfig
+ }
+ if len(item.ConfigFileParams) != 0 {
+ if updatedConfig, err = configctrl.ApplyParameters(item, baseConfig, taskCtx.configRender, taskCtx.paramsDefs); err != nil {
+ return failStatus(err)
+ }
+ }
+ if err = persistUpdatedParameters(fetcher.ResourceCtx, taskCtx.component, taskCtx.configRender, updatedConfig, configMap, fetcher.ComponentParameterObj, item, revision); err != nil {
+ return failStatus(err)
}
+
+ status.Message = nil
+ status.Phase = parametersv1alpha1.CMergedPhase
status.UpdateRevision = revision
+ return nil
+}
+
+// persistUpdatedParameters merges and updates parameter-related configmaps.
+// It first calls mergeAndApplyConfig to merge and update the configmap.
+// If the updatedConfig is nil, it returns nil. Otherwise, it calls updateInjectedEnvVars
+// to check and update the injected environment variables.
+func persistUpdatedParameters(rctx *render.ResourceCtx,
+ comp *component.SynthesizedComponent,
+ configRender *parametersv1alpha1.ParameterDrivenConfigRender,
+ updatedConfig *corev1.ConfigMap,
+ original *corev1.ConfigMap,
+ owner client.Object,
+ item parametersv1alpha1.ConfigTemplateItemDetail,
+ revision string) error {
+ if err := mergeAndApplyConfig(rctx, updatedConfig, original, owner, item, revision); err != nil {
+ return err
+ }
+ if updatedConfig == nil {
+ return nil
+ }
+ return updateInjectedEnvVars(rctx, comp, configRender, updatedConfig, owner, item, revision)
+}
+
+func updateInjectedEnvVars(rctx *render.ResourceCtx,
+ comp *component.SynthesizedComponent,
+ configRender *parametersv1alpha1.ParameterDrivenConfigRender,
+ config *corev1.ConfigMap,
+ owner client.Object,
+ item parametersv1alpha1.ConfigTemplateItemDetail,
+ revision string) error {
+ getOriginal := func(key types.NamespacedName) (*corev1.ConfigMap, error) {
+ var err error
+ var cmObj = &corev1.ConfigMap{}
+ err = rctx.Client.Get(rctx.Context, key, cmObj)
+ if err != nil && apierrors.IsNotFound(err) {
+ return nil, nil
+ }
+ return cmObj, err
+ }
+
+ envObjs, err := configctrl.InjectTemplateEnvFrom(comp, nil, configRender, []*corev1.ConfigMap{config})
+ if err != nil {
+ return err
+ }
+
+ var original *corev1.ConfigMap
+ for _, obj := range envObjs {
+ if original, err = getOriginal(client.ObjectKeyFromObject(obj)); err != nil {
+ return err
+ }
+ if original == nil {
+ err = errors.Join(err, create(rctx.Context, rctx.Client, obj, updateReconcileObject(item, owner, revision)))
+ } else {
+ err = errors.Join(err, update(rctx.Context, rctx.Client, original, original, mergedConfigmap(obj, updateReconcileObject(item, owner, revision))))
+ }
+ }
return err
}
+func mergeAndApplyConfig(resourceCtx *render.ResourceCtx,
+ expected *corev1.ConfigMap,
+ running *corev1.ConfigMap,
+ owner client.Object,
+ item parametersv1alpha1.ConfigTemplateItemDetail,
+ revision string) error {
+ switch {
+ case expected == nil: // not update
+ return update(resourceCtx.Context, resourceCtx.Client, running, running, updateReconcileObject(item, owner, revision))
+ case running == nil: // cm been deleted
+ return create(resourceCtx.Context, resourceCtx.Client, expected, updateReconcileObject(item, owner, revision))
+ default:
+ return update(resourceCtx.Context, resourceCtx.Client, running, running, mergedConfigmap(expected, updateReconcileObject(item, owner, revision)))
+ }
+}
+
+func mergedConfigmap(expected *corev1.ConfigMap, setter func(*corev1.ConfigMap) error) func(*corev1.ConfigMap) error {
+ return func(cmObj *corev1.ConfigMap) error {
+ cmObj.Data = expected.Data
+ cmObj.Labels = intctrlutil.MergeMetadataMaps(expected.Labels, cmObj.Labels)
+ cmObj.Annotations = intctrlutil.MergeMetadataMaps(expected.Annotations, cmObj.Annotations)
+ return setter(cmObj)
+ }
+}
+
+func update(ctx context.Context, cli client.Client, expected, origin *corev1.ConfigMap, setter func(*corev1.ConfigMap) error) error {
+ objectDeep := expected.DeepCopy()
+ if err := setter(objectDeep); err != nil {
+ return err
+ }
+ if reflect.DeepEqual(objectDeep.Data, origin.Data) &&
+ reflect.DeepEqual(objectDeep.Annotations, origin.Annotations) &&
+ reflect.DeepEqual(objectDeep.Labels, origin.Labels) &&
+ reflect.DeepEqual(objectDeep.Finalizers, origin.Finalizers) &&
+ reflect.DeepEqual(objectDeep.OwnerReferences, origin.OwnerReferences) {
+ return nil
+ }
+ return cli.Patch(ctx, objectDeep, client.MergeFrom(origin))
+}
+
+func create(ctx context.Context, cli client.Client, expected *corev1.ConfigMap, setter func(*corev1.ConfigMap) error) error {
+ if err := setter(expected); err != nil {
+ return err
+ }
+ return cli.Create(ctx, expected)
+}
+
+func updateReconcileObject(item parametersv1alpha1.ConfigTemplateItemDetail,
+ owner client.Object,
+ revision string) func(*corev1.ConfigMap) error {
+ return func(cmObj *corev1.ConfigMap) error {
+ if !controllerutil.ContainsFinalizer(cmObj, constant.ConfigFinalizerName) {
+ controllerutil.AddFinalizer(cmObj, constant.ConfigFinalizerName)
+ }
+ if !model.IsOwnerOf(owner, cmObj) {
+ if err := intctrlutil.SetControllerReference(owner, cmObj); err != nil {
+ return err
+ }
+ }
+ return updateConfigLabels(cmObj, item, revision)
+ }
+}
+
+func updateConfigLabels(obj *corev1.ConfigMap,
+ item parametersv1alpha1.ConfigTemplateItemDetail,
+ revision string) error {
+ if obj.Annotations == nil {
+ obj.Annotations = make(map[string]string)
+ }
+ b, err := json.Marshal(&item)
+ if err != nil {
+ return err
+ }
+ obj.Annotations[constant.ConfigAppliedVersionAnnotationKey] = string(b)
+ obj.Annotations[constant.ConfigurationRevision] = revision
+
+ if obj.Labels == nil {
+ obj.Labels = make(map[string]string)
+ }
+ hash, _ := cfgutil.ComputeHash(obj.Data)
+ obj.Labels[constant.CMInsConfigurationHashLabelKey] = hash
+ obj.Labels[constant.CMConfigurationSpecProviderLabelKey] = item.Name
+ obj.Labels[constant.CMConfigurationTemplateNameLabelKey] = item.ConfigSpec.TemplateRef
+ return nil
+}
+
func syncStatus(configMap *corev1.ConfigMap, status *parametersv1alpha1.ConfigTemplateItemDetailStatus) (err error) {
annotations := configMap.GetAnnotations()
// status.CurrentRevision = GetCurrentRevision(annotations)
@@ -209,13 +376,3 @@ func prepareReconcileTask(reqCtx intctrlutil.RequestCtx, cli client.Client, comp
fetcherTask.ComponentParameterObj = componentParameter
return fetcherTask, err
}
-
-func fromResourceCtx(ctx *render.ResourceCtx) *render.ResourceCtx {
- return &render.ResourceCtx{
- Context: ctx.Context,
- Client: ctx.Client,
- Namespace: ctx.Namespace,
- ClusterName: ctx.ClusterName,
- ComponentName: ctx.ComponentName,
- }
-}
diff --git a/controllers/parameters/suite_test.go b/controllers/parameters/suite_test.go
index e0a00261af4..d92850debc3 100644
--- a/controllers/parameters/suite_test.go
+++ b/controllers/parameters/suite_test.go
@@ -154,6 +154,13 @@ var _ = BeforeSuite(func() {
}).SetupWithManager(k8sManager, nil)
Expect(err).ToNot(HaveOccurred())
+ err = (&ComponentDrivenParameterReconciler{
+ Client: k8sManager.GetClient(),
+ Scheme: k8sManager.GetScheme(),
+ Recorder: k8sManager.GetEventRecorderFor("component-parameter-controller"),
+ }).SetupWithManager(k8sManager)
+ Expect(err).ToNot(HaveOccurred())
+
testCtx = testutil.NewDefaultTestContext(ctx, k8sClient, testEnv)
go func() {
diff --git a/controllers/trace/desired_state_handler_test.go b/controllers/trace/desired_state_handler_test.go
index 44f24b36b3b..b6181379eb9 100644
--- a/controllers/trace/desired_state_handler_test.go
+++ b/controllers/trace/desired_state_handler_test.go
@@ -34,8 +34,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
tracev1 "github.com/apecloud/kubeblocks/apis/trace/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/kubebuilderx"
@@ -271,9 +271,9 @@ var _ = Describe("desired_state_handler test", func() {
return apierrors.NewNotFound(kbappsv1.Resource(kbappsv1.ComponentKind), objKey.Name)
}).AnyTimes()
k8sMock.EXPECT().
- Get(gomock.Any(), gomock.Any(), &appsv1alpha1.Configuration{}, gomock.Any()).
- DoAndReturn(func(_ context.Context, objKey client.ObjectKey, obj *appsv1alpha1.Configuration, _ ...client.GetOption) error {
- return apierrors.NewNotFound(appsv1alpha1.Resource(constant.ConfigurationKind), objKey.Name)
+ Get(gomock.Any(), gomock.Any(), ¶metersv1alpha1.ComponentParameter{}, gomock.Any()).
+ DoAndReturn(func(_ context.Context, objKey client.ObjectKey, obj *parametersv1alpha1.ComponentParameter, _ ...client.GetOption) error {
+ return apierrors.NewNotFound(parametersv1alpha1.Resource(constant.ComponentParameterKind), objKey.Name)
}).AnyTimes()
k8sMock.EXPECT().
Get(gomock.Any(), gomock.Any(), &corev1.ConfigMap{}, gomock.Any()).
diff --git a/controllers/trace/dry_run_handler_test.go b/controllers/trace/dry_run_handler_test.go
index 120a3cdf33b..d484e73dea8 100644
--- a/controllers/trace/dry_run_handler_test.go
+++ b/controllers/trace/dry_run_handler_test.go
@@ -36,8 +36,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
tracev1 "github.com/apecloud/kubeblocks/apis/trace/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
"github.com/apecloud/kubeblocks/pkg/controller/kubebuilderx"
@@ -264,9 +264,9 @@ var _ = Describe("dry_run_handler test", func() {
return apierrors.NewNotFound(kbappsv1.Resource(kbappsv1.ComponentKind), objKey.Name)
}).AnyTimes()
k8sMock.EXPECT().
- Get(gomock.Any(), gomock.Any(), &appsv1alpha1.Configuration{}, gomock.Any()).
- DoAndReturn(func(_ context.Context, objKey client.ObjectKey, obj *appsv1alpha1.Configuration, _ ...client.GetOption) error {
- return apierrors.NewNotFound(appsv1alpha1.Resource(constant.ConfigurationKind), objKey.Name)
+ Get(gomock.Any(), gomock.Any(), ¶metersv1alpha1.ComponentParameter{}, gomock.Any()).
+ DoAndReturn(func(_ context.Context, objKey client.ObjectKey, obj *parametersv1alpha1.ComponentParameter, _ ...client.GetOption) error {
+ return apierrors.NewNotFound(parametersv1alpha1.Resource(constant.ComponentParameterKind), objKey.Name)
}).AnyTimes()
k8sMock.EXPECT().
Get(gomock.Any(), gomock.Any(), &corev1.ConfigMap{}, gomock.Any()).
diff --git a/controllers/trace/reconciler_tree.go b/controllers/trace/reconciler_tree.go
index a8fcbe1fb1f..9ced3b00b4e 100644
--- a/controllers/trace/reconciler_tree.go
+++ b/controllers/trace/reconciler_tree.go
@@ -41,8 +41,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
tracev1 "github.com/apecloud/kubeblocks/apis/trace/v1"
workloadsAPI "github.com/apecloud/kubeblocks/apis/workloads/v1"
"github.com/apecloud/kubeblocks/controllers/apps"
@@ -64,24 +64,24 @@ type ReconcilerTree interface {
type reconcilerFunc func(client.Client, record.EventRecorder) reconcile.Reconciler
var reconcilerFuncMap = map[tracev1.ObjectType]reconcilerFunc{
- objectType(kbappsv1.SchemeGroupVersion.String(), kbappsv1.ClusterKind): newClusterReconciler,
- objectType(kbappsv1.SchemeGroupVersion.String(), kbappsv1.ComponentKind): newComponentReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.SecretKind): newSecretReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.ServiceKind): newServiceReconciler,
- objectType(workloadsAPI.SchemeGroupVersion.String(), workloadsAPI.InstanceSetKind): newInstanceSetReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.ConfigMapKind): newConfigMapReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.PersistentVolumeClaimKind): newPVCReconciler,
- objectType(rbacv1.SchemeGroupVersion.String(), constant.RoleBindingKind): newRoleBindingReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.ServiceAccountKind): newSAReconciler,
- objectType(batchv1.SchemeGroupVersion.String(), constant.JobKind): newJobReconciler,
- objectType(dpv1alpha1.SchemeGroupVersion.String(), types.BackupKind): newBackupReconciler,
- objectType(dpv1alpha1.SchemeGroupVersion.String(), types.RestoreKind): newRestoreReconciler,
- objectType(appsv1alpha1.SchemeGroupVersion.String(), constant.ConfigurationKind): newConfigurationReconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.PodKind): newPodReconciler,
- objectType(appsv1.SchemeGroupVersion.String(), constant.StatefulSetKind): newSTSReconciler,
- objectType(vsv1.SchemeGroupVersion.String(), constant.VolumeSnapshotKind): newVolumeSnapshotV1Reconciler,
- objectType(vsv1beta1.SchemeGroupVersion.String(), constant.VolumeSnapshotKind): newVolumeSnapshotV1Beta1Reconciler,
- objectType(corev1.SchemeGroupVersion.String(), constant.PersistentVolumeKind): newPVReconciler,
+ objectType(kbappsv1.SchemeGroupVersion.String(), kbappsv1.ClusterKind): newClusterReconciler,
+ objectType(kbappsv1.SchemeGroupVersion.String(), kbappsv1.ComponentKind): newComponentReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.SecretKind): newSecretReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.ServiceKind): newServiceReconciler,
+ objectType(workloadsAPI.SchemeGroupVersion.String(), workloadsAPI.InstanceSetKind): newInstanceSetReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.ConfigMapKind): newConfigMapReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.PersistentVolumeClaimKind): newPVCReconciler,
+ objectType(rbacv1.SchemeGroupVersion.String(), constant.RoleBindingKind): newRoleBindingReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.ServiceAccountKind): newSAReconciler,
+ objectType(batchv1.SchemeGroupVersion.String(), constant.JobKind): newJobReconciler,
+ objectType(dpv1alpha1.SchemeGroupVersion.String(), types.BackupKind): newBackupReconciler,
+ objectType(dpv1alpha1.SchemeGroupVersion.String(), types.RestoreKind): newRestoreReconciler,
+ objectType(parametersv1alpha1.SchemeGroupVersion.String(), constant.ComponentParameterKind): newConfigurationReconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.PodKind): newPodReconciler,
+ objectType(appsv1.SchemeGroupVersion.String(), constant.StatefulSetKind): newSTSReconciler,
+ objectType(vsv1.SchemeGroupVersion.String(), constant.VolumeSnapshotKind): newVolumeSnapshotV1Reconciler,
+ objectType(vsv1beta1.SchemeGroupVersion.String(), constant.VolumeSnapshotKind): newVolumeSnapshotV1Beta1Reconciler,
+ objectType(corev1.SchemeGroupVersion.String(), constant.PersistentVolumeKind): newPVReconciler,
}
type reconcilerTree struct {
diff --git a/controllers/trace/suite_test.go b/controllers/trace/suite_test.go
index 35023e8c896..6195e011b3b 100644
--- a/controllers/trace/suite_test.go
+++ b/controllers/trace/suite_test.go
@@ -42,10 +42,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"
kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
- appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
opsv1alpha1 "github.com/apecloud/kubeblocks/apis/operations/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
tracev1 "github.com/apecloud/kubeblocks/apis/trace/v1"
workloadsv1 "github.com/apecloud/kubeblocks/apis/workloads/v1"
"github.com/apecloud/kubeblocks/pkg/controller/builder"
@@ -93,17 +92,13 @@ var _ = BeforeSuite(func() {
initKBOwnershipRulesForTest(cfg)
- err = appsv1alpha1.AddToScheme(scheme.Scheme)
- Expect(err).NotTo(HaveOccurred())
- model.AddScheme(appsv1alpha1.AddToScheme)
-
err = opsv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
model.AddScheme(opsv1alpha1.AddToScheme)
- err = appsv1beta1.AddToScheme(scheme.Scheme)
+ err = parametersv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
- model.AddScheme(appsv1beta1.AddToScheme)
+ model.AddScheme(parametersv1alpha1.AddToScheme)
err = kbappsv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
@@ -178,7 +173,7 @@ func mockObjects(k8sMock *mocks.MockClient) (*kbappsv1.Cluster, []kbappsv1.Compo
&batchv1.JobList{},
&dpv1alpha1.BackupList{},
&dpv1alpha1.RestoreList{},
- &appsv1alpha1.ConfigurationList{},
+ ¶metersv1alpha1.ComponentParameterList{},
}
for _, secondary := range componentSecondaries {
k8sMock.EXPECT().
diff --git a/controllers/trace/type.go b/controllers/trace/type.go
index 146bdc618f6..b06439aff77 100644
--- a/controllers/trace/type.go
+++ b/controllers/trace/type.go
@@ -39,8 +39,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
tracev1 "github.com/apecloud/kubeblocks/apis/trace/v1"
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
"github.com/apecloud/kubeblocks/pkg/constant"
@@ -159,7 +159,7 @@ var (
Criteria: componentCriteria,
},
{
- Secondary: objectType(appsv1alpha1.SchemeGroupVersion.String(), constant.ConfigurationKind),
+ Secondary: objectType(parametersv1alpha1.SchemeGroupVersion.String(), constant.ComponentParameterKind),
Criteria: componentCriteria,
},
},
@@ -186,7 +186,7 @@ var (
},
},
{
- Primary: objectType(kbappsv1.SchemeGroupVersion.String(), constant.ConfigurationKind),
+ Primary: objectType(parametersv1alpha1.SchemeGroupVersion.String(), constant.ComponentParameterKind),
OwnedResources: []OwnedResource{
{
Secondary: objectType(corev1.SchemeGroupVersion.String(), constant.ConfigMapKind),
diff --git a/pkg/constant/const.go b/pkg/constant/const.go
index ee517475f19..b37ea1f7fe8 100644
--- a/pkg/constant/const.go
+++ b/pkg/constant/const.go
@@ -43,7 +43,7 @@ const (
ConfigMapKind = "ConfigMap"
PersistentVolumeClaimKind = "PersistentVolumeClaim"
PersistentVolumeKind = "PersistentVolume"
- ConfigurationKind = "Configuration"
+ ComponentParameterKind = "ComponentParameter"
RoleBindingKind = "RoleBinding"
ServiceAccountKind = "ServiceAccount"
EventKind = "Event"
diff --git a/pkg/controller/component/service_reference_test.go b/pkg/controller/component/service_reference_test.go
index b05cf84304d..d07d585f21e 100644
--- a/pkg/controller/component/service_reference_test.go
+++ b/pkg/controller/component/service_reference_test.go
@@ -52,7 +52,6 @@ var _ = Describe("service references", func() {
// resources should be released in following order
// non-namespaced
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ClusterDefinitionSignature, true, ml)
- testapps.ClearResources(&testCtx, generics.ConfigConstraintSignature, ml)
// namespaced
testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ConfigMapSignature, true, inNS, ml)
diff --git a/pkg/controller/configuration/config_utils.go b/pkg/controller/configuration/config_utils.go
index c0e9cbcac72..606544575aa 100644
--- a/pkg/controller/configuration/config_utils.go
+++ b/pkg/controller/configuration/config_utils.go
@@ -22,13 +22,10 @@ package configuration
import (
"context"
"fmt"
- "reflect"
"slices"
"strings"
corev1 "k8s.io/api/core/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -38,7 +35,6 @@ import (
"github.com/apecloud/kubeblocks/pkg/configuration/core"
cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util"
"github.com/apecloud/kubeblocks/pkg/constant"
- "github.com/apecloud/kubeblocks/pkg/controller/builder"
"github.com/apecloud/kubeblocks/pkg/controller/component"
"github.com/apecloud/kubeblocks/pkg/controller/factory"
"github.com/apecloud/kubeblocks/pkg/controller/render"
@@ -46,28 +42,9 @@ import (
viper "github.com/apecloud/kubeblocks/pkg/viperx"
)
-func createConfigObjects(cli client.Client, ctx context.Context, objs []*corev1.ConfigMap) error {
- for _, obj := range objs {
- if err := cli.Create(ctx, obj, inDataContext()); err != nil {
-
- if !apierrors.IsAlreadyExists(err) {
- return err
- }
- // for update script cm
- if core.IsSchedulableConfigResource(obj) {
- continue
- }
- if err := cli.Update(ctx, obj, inDataContext()); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// buildConfigManagerWithComponent build the configmgr sidecar container and update it
+// BuildReloadActionContainer build the configmgr sidecar container and update it
// into PodSpec if configuration reload option is on
-func buildConfigManagerWithComponent(rctx *render.ResourceCtx, cluster *appsv1.Cluster, synthesizedComp *component.SynthesizedComponent, cmpd *appsv1.ComponentDefinition) error {
+func BuildReloadActionContainer(resourceCtx *render.ResourceCtx, cluster *appsv1.Cluster, synthesizedComp *component.SynthesizedComponent, cmpd *appsv1.ComponentDefinition, configmaps []*corev1.ConfigMap) error {
var (
err error
buildParams *cfgcm.CfgManagerBuildParams
@@ -82,12 +59,13 @@ func buildConfigManagerWithComponent(rctx *render.ResourceCtx, cluster *appsv1.C
if len(volumeDirs) == 0 {
return nil
}
- if configRender, paramsDefs, err = intctrlutil.ResolveCmpdParametersDefs(rctx.Context, rctx.Client, cmpd); err != nil {
+ if configRender, paramsDefs, err = resolveComponentParameterDefs(resourceCtx.Context, resourceCtx.Client, cmpd, configmaps, synthesizedComp); err != nil {
return err
}
if configRender == nil || len(configRender.Spec.Configs) == 0 {
return nil
}
+
configSpecMetas, err := cfgcm.GetSupportReloadConfigSpecs(usingConfigSpecs, configRender.Spec.Configs, paramsDefs)
if err != nil {
return err
@@ -98,7 +76,7 @@ func buildConfigManagerWithComponent(rctx *render.ResourceCtx, cluster *appsv1.C
if len(configSpecMetas) == 0 {
return nil
}
- if buildParams, err = buildConfigManagerParams(rctx.Client, rctx.Context, cluster, synthesizedComp, configSpecMetas, volumeDirs, podSpec); err != nil {
+ if buildParams, err = buildConfigManagerParams(resourceCtx.Client, resourceCtx.Context, cluster, synthesizedComp, configSpecMetas, volumeDirs, podSpec); err != nil {
return err
}
if buildParams == nil {
@@ -130,6 +108,34 @@ func buildConfigManagerWithComponent(rctx *render.ResourceCtx, cluster *appsv1.C
return nil
}
+func resolveComponentParameterDefs(ctx context.Context, cli client.Client, cmpd *appsv1.ComponentDefinition, configmaps []*corev1.ConfigMap, comp *component.SynthesizedComponent) (*parametersv1alpha1.ParameterDrivenConfigRender, []*parametersv1alpha1.ParametersDefinition, error) {
+ configRender, paramsDefs, err := intctrlutil.ResolveCmpdParametersDefs(ctx, cli, cmpd)
+ if err != nil {
+ return nil, nil, err
+ }
+ if err = handleInjectEnv(ctx, cli, comp, configRender, configmaps); err != nil {
+ return nil, nil, err
+ }
+ return configRender, paramsDefs, nil
+}
+
+func handleInjectEnv(ctx context.Context,
+ cli client.Client,
+ comp *component.SynthesizedComponent,
+ configRender *parametersv1alpha1.ParameterDrivenConfigRender,
+ configmaps []*corev1.ConfigMap) error {
+ envObjs, err := InjectTemplateEnvFrom(comp, comp.PodSpec, configRender, configmaps)
+ if err != nil {
+ return err
+ }
+ for _, obj := range envObjs {
+ if err = intctrlutil.IgnoreIsAlreadyExists(cli.Create(ctx, obj, inDataContext())); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
func checkAndUpdateSharProcessNamespace(podSpec *corev1.PodSpec, buildParams *cfgcm.CfgManagerBuildParams, configSpecMetas []cfgcm.ConfigSpecMeta) {
shared := cfgcm.NeedSharedProcessNamespace(configSpecMetas)
if shared {
@@ -324,67 +330,3 @@ func enableVScaleTrigger(configDescs []parametersv1alpha1.ComponentConfigDescrip
func enableTLSTrigger(configDescs []parametersv1alpha1.ComponentConfigDescription) bool {
return rerenderConfigEnabled(configDescs, parametersv1alpha1.ComponentTLSType)
}
-
-func runningComponentParameter(ctx context.Context, reader client.Reader, comp *component.SynthesizedComponent) (*parametersv1alpha1.ComponentParameter, error) {
- var componentParameter = ¶metersv1alpha1.ComponentParameter{}
-
- parameterKey := types.NamespacedName{
- Name: core.GenerateComponentConfigurationName(comp.ClusterName, comp.Name),
- Namespace: comp.Namespace,
- }
- if err := reader.Get(ctx, parameterKey, componentParameter); err != nil {
- return nil, client.IgnoreNotFound(err)
- }
- return componentParameter, nil
-}
-
-func buildComponentParameter(ctx context.Context, reader client.Reader, comp *component.SynthesizedComponent, owner *appsv1.Component, cmpd *appsv1.ComponentDefinition, configRender *parametersv1alpha1.ParameterDrivenConfigRender, paramsDefs []*parametersv1alpha1.ParametersDefinition) (*parametersv1alpha1.ComponentParameter, error) {
- tpls, err := resolveComponentTemplate(ctx, reader, cmpd)
- if err != nil {
- return nil, err
- }
-
- parameterObj := builder.NewComponentParameterBuilder(comp.Namespace,
- core.GenerateComponentConfigurationName(comp.ClusterName, comp.Name)).
- AddLabelsInMap(constant.GetCompLabelsWithDef(comp.ClusterName, comp.Name, cmpd.Name)).
- ClusterRef(comp.ClusterName).
- Component(comp.Name).
- SetConfigurationItem(ClassifyParamsFromConfigTemplate(intctrlutil.TransformComponentParameters(owner.Spec.InitParameters), cmpd, paramsDefs, tpls)).
- GetObject()
- if err = intctrlutil.SetOwnerReference(owner, parameterObj); err != nil {
- return nil, err
- }
- if configRender != nil {
- err = UpdateConfigPayload(¶meterObj.Spec, &owner.Spec, &configRender.Spec)
- }
- return parameterObj, err
-}
-
-func mergeComponentParameter(expected *parametersv1alpha1.ComponentParameter, existing *parametersv1alpha1.ComponentParameter) *parametersv1alpha1.ComponentParameter {
- return MergeComponentParameter(expected, existing, func(dest, expected *parametersv1alpha1.ConfigTemplateItemDetail) {
- if len(dest.ConfigFileParams) == 0 && len(expected.ConfigFileParams) != 0 {
- dest.ConfigFileParams = expected.ConfigFileParams
- }
- dest.Payload = expected.Payload
- })
-}
-
-func resolveComponentTemplate(ctx context.Context, reader client.Reader, cmpd *appsv1.ComponentDefinition) (map[string]*corev1.ConfigMap, error) {
- tpls := make(map[string]*corev1.ConfigMap, len(cmpd.Spec.Configs))
- for _, config := range cmpd.Spec.Configs {
- cm := &corev1.ConfigMap{}
- if err := reader.Get(ctx, client.ObjectKey{Name: config.TemplateRef, Namespace: config.Namespace}, cm); err != nil {
- return nil, err
- }
- tpls[config.Name] = cm
- }
- return tpls, nil
-}
-
-func updateComponentParameters(ctx context.Context, cli client.Client, expected, existing *parametersv1alpha1.ComponentParameter) error {
- mergedObject := mergeComponentParameter(expected, existing)
- if reflect.DeepEqual(mergedObject, existing) {
- return nil
- }
- return cli.Patch(ctx, mergedObject, client.MergeFrom(existing))
-}
diff --git a/pkg/controller/configuration/configuration_test.go b/pkg/controller/configuration/configuration_test.go
index ff93a1b7505..6f2c0d14a51 100644
--- a/pkg/controller/configuration/configuration_test.go
+++ b/pkg/controller/configuration/configuration_test.go
@@ -90,11 +90,6 @@ func newAllFieldsSynthesizedComponent(compDef *appsv1.ComponentDefinition, clust
return synthesizeComp
}
-func newAllFieldsComponent(cluster *appsv1.Cluster) *appsv1.Component {
- comp, _ := component.BuildComponent(cluster, &cluster.Spec.ComponentSpecs[0], nil, nil)
- return comp
-}
-
func addTestVolumeMount(spec *corev1.PodSpec, containerName string) {
for i := range spec.Containers {
container := &spec.Containers[i]
diff --git a/pkg/controller/configuration/operator.go b/pkg/controller/configuration/operator.go
deleted file mode 100644
index 2299755ed93..00000000000
--- a/pkg/controller/configuration/operator.go
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package configuration
-
-import (
- corev1 "k8s.io/api/core/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
-)
-
-type configOperator struct {
- render.ReconcileCtx
-}
-
-func NewConfigReconcileTask(resourceCtx *render.ResourceCtx,
- cluster *appsv1.Cluster,
- component *appsv1.Component,
- synthesizedComponent *component.SynthesizedComponent,
- podSpec *corev1.PodSpec,
- localObjs []client.Object,
-) *configOperator {
- return &configOperator{
- render.ReconcileCtx{
- ResourceCtx: resourceCtx,
- Cluster: cluster,
- Component: component,
- SynthesizedComponent: synthesizedComponent,
- PodSpec: podSpec,
- Cache: localObjs,
- },
- }
-}
-
-func (c *configOperator) Reconcile() error {
- var synthesizedComponent = c.SynthesizedComponent
-
- if len(synthesizedComponent.ConfigTemplates) == 0 && len(synthesizedComponent.ScriptTemplates) == 0 {
- return c.UpdateConfiguration()
- }
-
- return NewCreatePipeline(c.ReconcileCtx).
- ComponentAndComponentDef().
- Prepare().
- RenderScriptTemplate().
- SyncComponentParameter().
- ComponentParameter().
- CreateConfigTemplate().
- UpdatePodVolumes().
- BuildConfigManagerSidecar().
- UpdateConfigRelatedObject().
- Complete()
-}
-
-func (c *configOperator) UpdateConfiguration() error {
- return NewCreatePipeline(c.ReconcileCtx).
- ComponentAndComponentDef().
- SyncComponentParameter().
- UpdateConfigRelatedObject().
- Complete()
-}
diff --git a/pkg/controller/configuration/operator_test.go b/pkg/controller/configuration/operator_test.go
deleted file mode 100644
index a9873991584..00000000000
--- a/pkg/controller/configuration/operator_test.go
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package configuration
-
-import (
- . "github.com/onsi/ginkgo/v2"
- . "github.com/onsi/gomega"
-
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
- "github.com/apecloud/kubeblocks/pkg/controller/builder"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
- testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
- testutil "github.com/apecloud/kubeblocks/pkg/testutil/k8s"
- testparameters "github.com/apecloud/kubeblocks/pkg/testutil/parameters"
-)
-
-var _ = Describe("ConfigurationOperatorTest", func() {
- var clusterObj *appsv1.Cluster
- var compDefObj *appsv1.ComponentDefinition
- var componentObj *appsv1.Component
- var synthesizedComponent *component.SynthesizedComponent
- var configMapObj *corev1.ConfigMap
- var scriptsObj *corev1.ConfigMap
- var parametersDef *parametersv1alpha1.ParametersDefinition
- var configRender *parametersv1alpha1.ParameterDrivenConfigRender
- var componentParameter *parametersv1alpha1.ComponentParameter
- var k8sMockClient *testutil.K8sClientMockHelper
-
- createConfigReconcileTask := func() *configOperator {
- task := NewConfigReconcileTask(&render.ResourceCtx{
- Client: k8sMockClient.Client(),
- Context: ctx,
- Namespace: testCtx.DefaultNamespace,
- ClusterName: clusterName,
- ComponentName: mysqlCompName,
- },
- clusterObj,
- componentObj,
- synthesizedComponent,
- synthesizedComponent.PodSpec,
- nil)
- return task
- }
-
- BeforeEach(func() {
- // Add any setup steps that needs to be executed before each test
- k8sMockClient = testutil.NewK8sMockClient()
- clusterObj, compDefObj, _ = newAllFieldsClusterObj(nil, false)
- synthesizedComponent = newAllFieldsSynthesizedComponent(compDefObj, clusterObj)
- componentObj = newAllFieldsComponent(clusterObj)
- configMapObj = testapps.NewConfigMap("default", mysqlConfigName,
- testapps.SetConfigMapData("test", "test"))
- scriptsObj = testapps.NewConfigMap("default", mysqlScriptsTemplateName,
- testapps.SetConfigMapData("script.sh", "echo \"hello\""))
- componentParameter = builder.NewComponentParameterBuilder(testCtx.DefaultNamespace,
- cfgcore.GenerateComponentConfigurationName(clusterName, mysqlCompName)).
- ClusterRef(clusterName).
- Component(mysqlCompName).
- GetObject()
- parametersDef = testparameters.NewParametersDefinitionFactory(paramsDefName).GetObject()
- configRender = testparameters.NewParametersDrivenConfigFactory(pdcrName).
- SetComponentDefinition(compDefObj.Name).
- SetParametersDefs(paramsDefName).
- GetObject()
- parametersDef.Status.Phase = parametersv1alpha1.PDAvailablePhase
- configRender.Status.Phase = parametersv1alpha1.PDAvailablePhase
- })
-
- AfterEach(func() {
- k8sMockClient.Finish()
- })
-
- Context("ConfigOperatorTest", func() {
- It("NormalTest", func() {
- k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult(
- []client.Object{
- compDefObj,
- componentObj,
- clusterObj,
- scriptsObj,
- configMapObj,
- parametersDef,
- configRender,
- componentParameter,
- },
- ), testutil.WithAnyTimes()))
- k8sMockClient.MockCreateMethod(testutil.WithCreateReturned(testutil.WithCreatedSucceedResult(), testutil.WithAnyTimes()))
- k8sMockClient.MockPatchMethod(testutil.WithPatchReturned(func(obj client.Object, patch client.Patch) error {
- switch v := obj.(type) {
- case *parametersv1alpha1.ComponentParameter:
- if client.ObjectKeyFromObject(obj) == client.ObjectKeyFromObject(componentParameter) {
- componentParameter.Spec = *v.Spec.DeepCopy()
- componentParameter.Status = *v.Status.DeepCopy()
- }
- }
- return nil
- }))
- k8sMockClient.MockNListMethod(0, testutil.WithListReturned(
- testutil.WithConstructListReturnedResult([]runtime.Object{configRender}),
- testutil.WithAnyTimes(),
- ))
- Expect(createConfigReconcileTask().Reconcile()).Should(Succeed())
- })
-
- It("EmptyConfigSpecTest", func() {
-
- // k8sMockClient.MockCreateMethod(testutil.WithCreateReturned(testutil.WithCreatedSucceedResult(), testutil.WithTimes(1)))
- k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult(
- []client.Object{
- compDefObj,
- componentObj,
- clusterObj,
- configMapObj,
- componentParameter,
- },
- ), testutil.WithAnyTimes()))
- k8sMockClient.MockPatchMethod(testutil.WithSucceed(), testutil.WithAnyTimes())
- k8sMockClient.MockNListMethod(0, testutil.WithListReturned(
- testutil.WithConstructListReturnedResult([]runtime.Object{configRender}),
- testutil.WithAnyTimes(),
- ))
-
- synthesizedComponent.ConfigTemplates = nil
- synthesizedComponent.ScriptTemplates = nil
- Expect(createConfigReconcileTask().Reconcile()).Should(Succeed())
- })
-
- })
-
-})
diff --git a/pkg/controller/configuration/pipeline.go b/pkg/controller/configuration/pipeline.go
deleted file mode 100644
index 32aa0534ddf..00000000000
--- a/pkg/controller/configuration/pipeline.go
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package configuration
-
-import (
- "context"
- "strconv"
-
- corev1 "k8s.io/api/core/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- "github.com/apecloud/kubeblocks/pkg/configuration/core"
- "github.com/apecloud/kubeblocks/pkg/constant"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
- intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
- "github.com/apecloud/kubeblocks/pkg/generics"
-)
-
-type pipeline struct {
- // configuration *appsv1alpha1.Configuration
- renderWrapper renderWrapper
-
- ctx render.ReconcileCtx
- ResourceFetcher[pipeline]
-
- configRender *parametersv1alpha1.ParameterDrivenConfigRender
- parametersDefs []*parametersv1alpha1.ParametersDefinition
-}
-
-type updatePipeline struct {
- renderWrapper renderWrapper
-
- reconcile bool
- item parametersv1alpha1.ConfigTemplateItemDetail
- itemStatus *parametersv1alpha1.ConfigTemplateItemDetailStatus
- configSpec *appsv1.ComponentTemplateSpec
- // replace of ConfigMapObj
- // originalCM *corev1.ConfigMap
- newCM *corev1.ConfigMap
- configPatch *core.ConfigPatchInfo
-
- ctx render.ReconcileCtx
- ResourceFetcher[updatePipeline]
-
- configRender *parametersv1alpha1.ParameterDrivenConfigRender
- parametersDefs []*parametersv1alpha1.ParametersDefinition
-}
-
-func NewCreatePipeline(ctx render.ReconcileCtx) *pipeline {
- p := &pipeline{ctx: ctx}
- return p.Init(ctx.ResourceCtx, p)
-}
-
-func NewReconcilePipeline(ctx render.ReconcileCtx, item parametersv1alpha1.ConfigTemplateItemDetail, itemStatus *parametersv1alpha1.ConfigTemplateItemDetailStatus, cm *corev1.ConfigMap, componentParameter *parametersv1alpha1.ComponentParameter) *updatePipeline {
- p := &updatePipeline{
- reconcile: true,
- item: item,
- itemStatus: itemStatus,
- ctx: ctx,
- configSpec: item.ConfigSpec,
- }
- p.Init(ctx.ResourceCtx, p)
- p.ConfigMapObj = cm
- p.ComponentParameterObj = componentParameter
- return p
-}
-
-func (p *pipeline) Prepare() *pipeline {
- buildTemplate := func() (err error) {
- ctx := p.ctx
- p.renderWrapper = newTemplateRenderWrapper(p.Context, ctx.Client, render.NewTemplateBuilder(&ctx), ctx.Cluster, ctx.Component)
- p.configRender, p.parametersDefs, err = intctrlutil.ResolveCmpdParametersDefs(ctx.Context, ctx.Client, p.ComponentDefObj)
- return err
- }
-
- return p.Wrap(buildTemplate)
-}
-
-func (p *pipeline) RenderScriptTemplate() *pipeline {
- return p.Wrap(func() error {
- ctx := p.ctx
- return p.renderWrapper.renderScriptTemplate(ctx.Cluster, ctx.SynthesizedComponent, ctx.Cache, ctx.Component)
- })
-}
-
-func (p *pipeline) SyncComponentParameter() *pipeline {
- buildConfiguration := func() (err error) {
- var existingObject *parametersv1alpha1.ComponentParameter
- var expectedObject *parametersv1alpha1.ComponentParameter
-
- if existingObject, err = runningComponentParameter(p.Context, p.Client, p.ctx.SynthesizedComponent); err != nil {
- return err
- }
- if expectedObject, err = buildComponentParameter(p.Context, p.Client, p.ctx.SynthesizedComponent, p.ctx.Component, p.ComponentDefObj, p.configRender, p.parametersDefs); err != nil {
- return err
- }
-
- switch {
- case expectedObject == nil:
- return p.Client.Delete(p.Context, existingObject)
- case existingObject == nil:
- return p.Client.Create(p.Context, expectedObject)
- default:
- return updateComponentParameters(p.Context, p.Client, expectedObject, existingObject)
- }
- }
- return p.Wrap(buildConfiguration)
-}
-
-func (p *pipeline) CreateConfigTemplate() *pipeline {
- return p.Wrap(func() error {
- ctx := p.ctx
- revision := strconv.FormatInt(p.ComponentParameterObj.GetGeneration(), 10)
- return p.renderWrapper.renderConfigTemplate(ctx.Cluster, ctx.SynthesizedComponent, ctx.Cache, p.ComponentParameterObj, p.configRender, p.parametersDefs, revision)
- })
-}
-
-func (p *pipeline) UpdatePodVolumes() *pipeline {
- mapName := func(tpl appsv1.ComponentTemplateSpec) string {
- return tpl.Name
- }
- return p.Wrap(func() error {
- return intctrlutil.CreateOrUpdatePodVolumes(p.ctx.PodSpec,
- p.renderWrapper.volumes,
- generics.Map(p.ctx.SynthesizedComponent.ConfigTemplates, mapName))
- })
-}
-
-func (p *pipeline) BuildConfigManagerSidecar() *pipeline {
- return p.Wrap(func() error {
- return buildConfigManagerWithComponent(p.ctx.ResourceCtx, p.ctx.Cluster, p.ctx.SynthesizedComponent, p.ComponentDefObj)
- })
-}
-
-func (p *pipeline) UpdateConfigRelatedObject() *pipeline {
- updateMeta := func() error {
- if err := syncInjectEnvFromCM(p.Context, p.Client, p.ctx.SynthesizedComponent, p.configRender, p.renderWrapper.renderedObjs, true); err != nil {
- return err
- }
- return createConfigObjects(p.Client, p.Context, p.renderWrapper.renderedObjs)
- }
-
- return p.Wrap(updateMeta)
-}
-
-func (p *updatePipeline) isDone() bool {
- return !p.reconcile
-}
-
-func (p *updatePipeline) PrepareForTemplate() *updatePipeline {
- buildTemplate := func() (err error) {
- p.reconcile = !intctrlutil.IsApplyConfigChanged(p.ConfigMapObj, p.item)
- if p.isDone() {
- return
- }
- p.renderWrapper = newTemplateRenderWrapper(p.Context, p.Client, render.NewTemplateBuilder(&p.ctx), p.ctx.Cluster, p.ctx.Component)
- p.configRender, p.parametersDefs, err = intctrlutil.ResolveCmpdParametersDefs(p.Context, p.Client, p.ComponentDefObj)
- return
- }
- return p.Wrap(buildTemplate)
-}
-
-func (p *updatePipeline) RerenderTemplate() *updatePipeline {
- return p.Wrap(func() (err error) {
- if p.isDone() {
- return
- }
- if intctrlutil.IsRerender(p.ConfigMapObj, p.item) {
- p.newCM, err = p.renderWrapper.rerenderConfigTemplate(p.ctx.Cluster, p.ctx.SynthesizedComponent, *p.configSpec, &p.item, p.configRender, p.parametersDefs)
- } else {
- p.newCM = p.ConfigMapObj.DeepCopy()
- }
- return
- })
-}
-
-func (p *updatePipeline) ApplyParameters() *updatePipeline {
- patchMerge := func(p *updatePipeline, cm *corev1.ConfigMap, item parametersv1alpha1.ConfigTemplateItemDetail) error {
- if p.isDone() || len(item.ConfigFileParams) == 0 || p.configRender == nil {
- return nil
- }
- newData, err := DoMerge(cm.Data, item.ConfigFileParams, p.parametersDefs, p.configRender.Spec.Configs)
- if err != nil {
- return err
- }
- if p.configRender == nil {
- cm.Data = newData
- return nil
- }
-
- p.configPatch, _, err = core.CreateConfigPatch(cm.Data,
- newData,
- p.configRender.Spec,
- false)
- if err != nil {
- return err
- }
- cm.Data = newData
- return nil
- }
-
- return p.Wrap(func() error {
- if p.isDone() {
- return nil
- }
- return patchMerge(p, p.newCM, p.item)
- })
-}
-
-func (p *updatePipeline) UpdateConfigVersion(revision string) *updatePipeline {
- return p.Wrap(func() error {
- if p.isDone() {
- return nil
- }
-
- if err := updateConfigMetaForCM(p.newCM, &p.item, revision); err != nil {
- return err
- }
- annotations := p.newCM.Annotations
- if annotations == nil {
- annotations = make(map[string]string)
- }
-
- // delete disable reconcile annotation
- if _, ok := annotations[constant.DisableUpgradeInsConfigurationAnnotationKey]; ok {
- annotations[constant.DisableUpgradeInsConfigurationAnnotationKey] = strconv.FormatBool(false)
- }
- p.newCM.Annotations = annotations
- // p.itemStatus.UpdateRevision = revision
- return nil
- })
-}
-
-// TODO(leon)
-func (p *updatePipeline) Sync() *updatePipeline {
- return p.Wrap(func() error {
- if !p.isDone() {
- if err := syncInjectEnvFromCM(p.Context, p.Client, p.ctx.SynthesizedComponent, p.configRender, []*corev1.ConfigMap{p.newCM}, false); err != nil {
- return err
- }
- }
- if err := intctrlutil.SetControllerReference(p.ComponentParameterObj, p.newCM); err != nil {
- return err
- }
-
- switch {
- case p.isDone():
- return nil
- case p.ConfigMapObj == nil && p.newCM != nil:
- return p.Client.Create(p.Context, p.newCM)
- case p.ConfigMapObj != nil:
- patch := client.MergeFrom(p.ConfigMapObj)
- if p.ConfigMapObj != nil {
- p.newCM.Labels = intctrlutil.MergeMetadataMaps(p.newCM.Labels, p.ConfigMapObj.Labels)
- p.newCM.Annotations = intctrlutil.MergeMetadataMaps(p.newCM.Annotations, p.ConfigMapObj.Annotations)
- }
- return p.Client.Patch(p.Context, p.newCM, patch)
- }
- return core.MakeError("unexpected condition")
- })
-}
-
-func syncInjectEnvFromCM(ctx context.Context, cli client.Client, synthesizedComp *component.SynthesizedComponent, configRender *parametersv1alpha1.ParameterDrivenConfigRender, configMaps []*corev1.ConfigMap, onlyCreate bool) error {
- var podSpec *corev1.PodSpec
-
- if onlyCreate {
- podSpec = synthesizedComp.PodSpec
- }
- envObjs, err := InjectTemplateEnvFrom(synthesizedComp, podSpec, configRender, configMaps)
- if err != nil {
- return err
- }
- for _, obj := range envObjs {
- if err = cli.Create(ctx, obj, inDataContext()); err == nil {
- continue
- }
- if !apierrors.IsAlreadyExists(err) {
- return err
- }
- if onlyCreate {
- continue
- }
- if err = cli.Update(ctx, obj, inDataContext()); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/pkg/controller/configuration/pipeline_test.go b/pkg/controller/configuration/pipeline_test.go
deleted file mode 100644
index f250495596c..00000000000
--- a/pkg/controller/configuration/pipeline_test.go
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package configuration
-
-import (
- "context"
- "strconv"
-
- . "github.com/onsi/ginkgo/v2"
- . "github.com/onsi/gomega"
-
- "github.com/golang/mock/gomock"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
- cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util"
- "github.com/apecloud/kubeblocks/pkg/controller/builder"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
- testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
- testutil "github.com/apecloud/kubeblocks/pkg/testutil/k8s"
- testparameters "github.com/apecloud/kubeblocks/pkg/testutil/parameters"
-)
-
-var _ = Describe("ConfigurationPipelineTest", func() {
- const testConfigFile = "postgresql.conf"
-
- var clusterObj *appsv1.Cluster
- var componentObj *appsv1.Component
- var compDefObj *appsv1.ComponentDefinition
- var synthesizedComponent *component.SynthesizedComponent
- var configMapObj *corev1.ConfigMap
- var parametersDef *parametersv1alpha1.ParametersDefinition
- var componentParameter *parametersv1alpha1.ComponentParameter
- var configRender *parametersv1alpha1.ParameterDrivenConfigRender
- var k8sMockClient *testutil.K8sClientMockHelper
-
- mockAPIResource := func(lazyFetcher testutil.Getter) {
- k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult(
- []client.Object{
- compDefObj,
- clusterObj,
- clusterObj,
- configMapObj,
- parametersDef,
- componentObj,
- componentParameter,
- configRender,
- }, lazyFetcher), testutil.WithAnyTimes()))
- k8sMockClient.MockCreateMethod(testutil.WithCreateReturned(testutil.WithCreatedSucceedResult(), testutil.WithAnyTimes()))
- k8sMockClient.MockPatchMethod(testutil.WithPatchReturned(func(obj client.Object, patch client.Patch) error {
- switch v := obj.(type) {
- case *parametersv1alpha1.ComponentParameter:
- if client.ObjectKeyFromObject(obj) == client.ObjectKeyFromObject(componentParameter) {
- componentParameter.Spec = *v.Spec.DeepCopy()
- componentParameter.Status = *v.Status.DeepCopy()
- }
- }
- return nil
- }, testutil.WithAnyTimes()))
- k8sMockClient.MockNListMethod(0, testutil.WithListReturned(
- testutil.WithConstructListReturnedResult([]runtime.Object{configRender}),
- testutil.WithAnyTimes(),
- ))
- k8sMockClient.MockStatusMethod().
- EXPECT().
- Patch(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
- DoAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
- switch v := obj.(type) {
- case *parametersv1alpha1.ComponentParameter:
- if client.ObjectKeyFromObject(obj) == client.ObjectKeyFromObject(componentParameter) {
- componentParameter.Status = *v.Status.DeepCopy()
- }
- }
- return nil
- }).AnyTimes()
- }
-
- BeforeEach(func() {
- // Add any setup steps that needs to be executed before each test
- k8sMockClient = testutil.NewK8sMockClient()
- clusterObj, compDefObj, _ = newAllFieldsClusterObj(nil, false)
- componentObj = newAllFieldsComponent(clusterObj)
- synthesizedComponent = newAllFieldsSynthesizedComponent(compDefObj, clusterObj)
- configMapObj = testapps.NewConfigMap("default", mysqlConfigName,
- testapps.SetConfigMapData(testConfigFile, `
-bgwriter_delay = '200ms'
-bgwriter_flush_after = '64'
-bgwriter_lru_maxpages = '1000'
-bgwriter_lru_multiplier = '10.0'
-bytea_output = 'hex'
-check_function_bodies = 'True'
-checkpoint_completion_target = '0.9'
-checkpoint_flush_after = '32'
-checkpoint_timeout = '15min'
-max_connections = '1000'
-`))
- componentParameter = builder.NewComponentParameterBuilder(testCtx.DefaultNamespace,
- cfgcore.GenerateComponentConfigurationName(clusterName, mysqlCompName)).
- ClusterRef(clusterName).
- Component(mysqlCompName).
- GetObject()
-
- parametersDef = testparameters.NewParametersDefinitionFactory(paramsDefName).GetObject()
- configRender = testparameters.NewParametersDrivenConfigFactory(pdcrName).
- SetConfigDescription(testConfigFile, configTemplateName, parametersv1alpha1.FileFormatConfig{Format: parametersv1alpha1.Properties}).
- SetComponentDefinition(compDefObj.Name).
- SetParametersDefs(paramsDefName).
- GetObject()
- parametersDef.Status.Phase = parametersv1alpha1.PDAvailablePhase
- configRender.Status.Phase = parametersv1alpha1.PDAvailablePhase
- })
-
- AfterEach(func() {
- k8sMockClient.Finish()
- })
-
- Context("ConfigPipelineTest", func() {
- It("NormalTest", func() {
- By("create configuration resource")
- createPipeline := NewCreatePipeline(render.ReconcileCtx{
- ResourceCtx: &render.ResourceCtx{
- Client: k8sMockClient.Client(),
- Context: ctx,
- Namespace: testCtx.DefaultNamespace,
- ClusterName: clusterName,
- ComponentName: mysqlCompName,
- },
- Cluster: clusterObj,
- Component: componentObj,
- SynthesizedComponent: synthesizedComponent,
- PodSpec: synthesizedComponent.PodSpec,
- })
-
- By("mock api resource for configuration")
- mockAPIResource(func(key client.ObjectKey, obj client.Object) (bool, error) {
- switch obj.(type) {
- case *corev1.ConfigMap:
- for _, renderedObj := range createPipeline.renderWrapper.renderedObjs {
- if client.ObjectKeyFromObject(renderedObj) == key {
- testutil.SetGetReturnedObject(obj, renderedObj)
- return true, nil
- }
- }
- }
- return false, nil
- })
-
- err := createPipeline.
- ComponentAndComponentDef().
- Prepare().
- SyncComponentParameter().
- ComponentParameter().
- CreateConfigTemplate().
- UpdatePodVolumes().
- BuildConfigManagerSidecar().
- UpdateConfigRelatedObject().
- Complete()
- Expect(err).Should(Succeed())
-
- By("update configuration resource for mocking reconfiguring")
- item := componentParameter.Spec.ConfigItemDetails[0]
- status := ¶metersv1alpha1.ConfigTemplateItemDetailStatus{
- Name: item.Name,
- Phase: parametersv1alpha1.CInitPhase,
- }
- item.ConfigFileParams = map[string]parametersv1alpha1.ParametersInFile{
- testConfigFile: {
- Parameters: map[string]*string{
- "max_connections": cfgutil.ToPointer("2000"),
- },
- },
- "other.conf": {
- Content: cfgutil.ToPointer(`for test`),
- },
- }
- reconcileTask := NewReconcilePipeline(render.ReconcileCtx{
- ResourceCtx: createPipeline.ResourceCtx,
- Cluster: clusterObj,
- Component: componentObj,
- SynthesizedComponent: synthesizedComponent,
- PodSpec: synthesizedComponent.PodSpec,
- }, item, status, configMapObj, componentParameter)
-
- By("update configuration resource")
- err = reconcileTask.
- ComponentAndComponentDef().
- PrepareForTemplate().
- RerenderTemplate().
- ApplyParameters().
- UpdateConfigVersion(strconv.FormatInt(reconcileTask.ComponentParameterObj.GetGeneration(), 10)).
- Sync().
- Complete()
- Expect(err).Should(Succeed())
- })
- })
-
-})
diff --git a/pkg/controller/configuration/resource_wrapper.go b/pkg/controller/configuration/resource_wrapper.go
index b327a591786..75d1a6470b1 100644
--- a/pkg/controller/configuration/resource_wrapper.go
+++ b/pkg/controller/configuration/resource_wrapper.go
@@ -28,8 +28,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
- appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1"
parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
"github.com/apecloud/kubeblocks/pkg/constant"
@@ -46,10 +44,7 @@ type ResourceFetcher[T any] struct {
ComponentDefObj *appsv1.ComponentDefinition
ClusterComObj *appsv1.ClusterComponentSpec
- ConfigMapObj *corev1.ConfigMap
- ConfigurationObj *appsv1alpha1.Configuration
- ConfigConstraintObj *appsv1beta1.ConfigConstraint
-
+ ConfigMapObj *corev1.ConfigMap
ComponentParameterObj *parametersv1alpha1.ComponentParameter
}
@@ -121,22 +116,6 @@ func (r *ResourceFetcher[T]) ComponentSpec() *T {
})
}
-func (r *ResourceFetcher[T]) Configuration() *T {
- configKey := client.ObjectKey{
- Name: cfgcore.GenerateComponentConfigurationName(r.ClusterName, r.ComponentName),
- Namespace: r.Namespace,
- }
- return r.Wrap(func() (err error) {
- configuration := appsv1alpha1.Configuration{}
- err = r.Client.Get(r.Context, configKey, &configuration)
- if err != nil {
- return client.IgnoreNotFound(err)
- }
- r.ConfigurationObj = &configuration
- return
- })
-}
-
func (r *ResourceFetcher[T]) ConfigMap(configSpec string) *T {
cmKey := client.ObjectKey{
Name: cfgcore.GetComponentCfgName(r.ClusterName, r.ComponentName, configSpec),
@@ -149,16 +128,6 @@ func (r *ResourceFetcher[T]) ConfigMap(configSpec string) *T {
})
}
-func (r *ResourceFetcher[T]) ConfigConstraints(ccName string) *T {
- return r.Wrap(func() error {
- if ccName != "" {
- r.ConfigConstraintObj = &appsv1beta1.ConfigConstraint{}
- return r.Client.Get(r.Context, client.ObjectKey{Name: ccName}, r.ConfigConstraintObj)
- }
- return nil
- })
-}
-
func (r *ResourceFetcher[T]) ComponentParameter() *T {
configKey := client.ObjectKey{
Name: cfgcore.GenerateComponentConfigurationName(r.ClusterName, r.ComponentName),
diff --git a/pkg/controller/configuration/resource_wrapper_test.go b/pkg/controller/configuration/resource_wrapper_test.go
index 25435694ede..68bef7e9dc4 100644
--- a/pkg/controller/configuration/resource_wrapper_test.go
+++ b/pkg/controller/configuration/resource_wrapper_test.go
@@ -25,12 +25,11 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1"
cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/controller/builder"
"github.com/apecloud/kubeblocks/pkg/controller/render"
testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
testutil "github.com/apecloud/kubeblocks/pkg/testutil/k8s"
@@ -71,19 +70,14 @@ var _ = Describe("resource Fetcher", func() {
[]client.Object{
cluster,
testapps.NewConfigMap("default", cfgcore.GetComponentCfgName(clusterName, mysqlCompName, mysqlConfigName)),
- &appsv1beta1.ConfigConstraint{
- ObjectMeta: metav1.ObjectMeta{
- Name: mysqlConfigName,
- },
- },
+ builder.NewComponentParameterBuilder(testCtx.DefaultNamespace, cfgcore.GenerateComponentConfigurationName(clusterName, mysqlCompName)).GetObject(),
},
), testutil.WithAnyTimes()))
err := NewTest(k8sMockClient.Client(), ctx).
Cluster().
ComponentSpec().
ConfigMap(mysqlConfigName).
- ConfigConstraints(mysqlConfigName).
- Configuration().
+ ComponentParameter().
Complete()
Expect(err).Should(Succeed())
})
diff --git a/pkg/controller/configuration/template_render.go b/pkg/controller/configuration/template_render.go
new file mode 100644
index 00000000000..4f87271aa39
--- /dev/null
+++ b/pkg/controller/configuration/template_render.go
@@ -0,0 +1,77 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+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 configuration
+
+import (
+ "fmt"
+
+ corev1 "k8s.io/api/core/v1"
+
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
+ configcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/controller/render"
+)
+
+func RerenderParametersTemplate(reconcileCtx *render.ReconcileCtx,
+ item parametersv1alpha1.ConfigTemplateItemDetail,
+ configRender *parametersv1alpha1.ParameterDrivenConfigRender,
+ parametersDefs []*parametersv1alpha1.ParametersDefinition) (*corev1.ConfigMap, error) {
+ parametersValidate := func(m map[string]string) error {
+ return validateRenderedData(m, parametersDefs, configRender)
+ }
+
+ configSpec := *item.ConfigSpec
+ templateRender := render.NewTemplateBuilder(reconcileCtx)
+ rerenderCMObj, err := templateRender.RenderComponentTemplate(configSpec,
+ configcore.GetComponentCfgName(reconcileCtx.SynthesizedComponent.ClusterName,
+ reconcileCtx.SynthesizedComponent.Name,
+ item.ConfigSpec.Name),
+ parametersValidate)
+ if err != nil {
+ return nil, err
+ }
+ if item.CustomTemplates == nil {
+ return rerenderCMObj, nil
+ }
+
+ mergedData, err := mergerConfigTemplate(*item.CustomTemplates,
+ templateRender,
+ configSpec,
+ rerenderCMObj.Data,
+ parametersDefs,
+ configRender)
+ if err != nil {
+ return nil, err
+ }
+ rerenderCMObj.Data = mergedData
+ return rerenderCMObj, nil
+}
+
+func ApplyParameters(item parametersv1alpha1.ConfigTemplateItemDetail, orig *corev1.ConfigMap, configRender *parametersv1alpha1.ParameterDrivenConfigRender, paramsDefs []*parametersv1alpha1.ParametersDefinition) (*corev1.ConfigMap, error) {
+ if configRender == nil || len(configRender.Spec.Configs) == 0 {
+ return nil, fmt.Errorf("not support parameter reconfigure")
+ }
+
+ newData, err := DoMerge(orig.Data, item.ConfigFileParams, paramsDefs, configRender.Spec.Configs)
+ if err != nil {
+ return nil, err
+ }
+
+ expected := orig.DeepCopy()
+ expected.Data = newData
+ return expected, nil
+}
diff --git a/pkg/controller/configuration/template_render_test.go b/pkg/controller/configuration/template_render_test.go
new file mode 100644
index 00000000000..2359f8ea2d4
--- /dev/null
+++ b/pkg/controller/configuration/template_render_test.go
@@ -0,0 +1,165 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+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 configuration
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
+ cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/controller/component"
+ "github.com/apecloud/kubeblocks/pkg/controller/render"
+ testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
+ testutil "github.com/apecloud/kubeblocks/pkg/testutil/k8s"
+ testparameters "github.com/apecloud/kubeblocks/pkg/testutil/parameters"
+ "github.com/apecloud/kubeblocks/pkg/unstructured"
+)
+
+var _ = Describe("ToolsImageBuilderTest", func() {
+
+ var mockK8sCli *testutil.K8sClientMockHelper
+ var clusterObj *appsv1.Cluster
+ var compDefObj *appsv1.ComponentDefinition
+ var clusterComponent *component.SynthesizedComponent
+ var paramsDef *parametersv1alpha1.ParametersDefinition
+ var pdcr *parametersv1alpha1.ParameterDrivenConfigRender
+
+ BeforeEach(func() {
+ mockK8sCli = testutil.NewK8sMockClient()
+
+ // Add any setup steps that needs to be executed before each test
+ clusterObj, compDefObj, _ = newAllFieldsClusterObj(nil, false)
+ paramsDef = testparameters.NewParametersDefinitionFactory(paramsDefName).
+ SetReloadAction(testparameters.WithNoneAction()).
+ GetObject()
+ clusterComponent = newAllFieldsSynthesizedComponent(compDefObj, clusterObj)
+
+ pdcr = testparameters.NewParametersDrivenConfigFactory(pdcrName).
+ SetParametersDefs(paramsDef.Name).
+ SetComponentDefinition(compDefObj.GetName()).
+ SetTemplateName(configTemplateName).
+ GetObject()
+ })
+
+ AfterEach(func() {
+ // Add any teardown steps that needs to be executed after each test
+ mockK8sCli.Finish()
+ })
+
+ deRef := func(m map[string]*parametersv1alpha1.ParametersInFile) map[string]parametersv1alpha1.ParametersInFile {
+ r := make(map[string]parametersv1alpha1.ParametersInFile, len(m))
+ for key, param := range m {
+ r[key] = *param
+ }
+ return r
+ }
+
+ rerender := func(parameters parametersv1alpha1.ComponentParameters, tpl *corev1.ConfigMap, customTemplate *appsv1.ConfigTemplateExtension) unstructured.ConfigObject {
+ rctx := &render.ReconcileCtx{
+ ResourceCtx: &render.ResourceCtx{
+ Context: testCtx.Ctx,
+ Client: mockK8sCli.Client(),
+ ClusterName: clusterObj.Name,
+ ComponentName: mysqlCompName,
+ },
+ Cluster: clusterObj,
+ SynthesizedComponent: clusterComponent,
+ PodSpec: &corev1.PodSpec{},
+ }
+ item := parametersv1alpha1.ConfigTemplateItemDetail{
+ Name: configTemplateName,
+ ConfigSpec: &appsv1.ComponentTemplateSpec{
+ Name: configTemplateName,
+ Namespace: testCtx.DefaultNamespace,
+ TemplateRef: mysqlConfigName,
+ VolumeName: testapps.ConfVolumeName,
+ },
+ CustomTemplates: customTemplate,
+ }
+ pds := []*parametersv1alpha1.ParametersDefinition{paramsDef}
+ cmObj, err := RerenderParametersTemplate(rctx, item, pdcr, pds)
+ Expect(err).Should(Succeed())
+ configdesc := pdcr.Spec.Configs[0]
+ if len(parameters) == 0 {
+ configReaders, err := cfgcore.LoadRawConfigObject(cmObj.Data, configdesc.FileFormatConfig, []string{configdesc.Name})
+ Expect(err).Should(Succeed())
+ return configReaders[configdesc.Name]
+ }
+ params := ClassifyComponentParameters(parameters, pds, []appsv1.ComponentTemplateSpec{*item.ConfigSpec}, map[string]*corev1.ConfigMap{configTemplateName: tpl})
+
+ tplParams, ok := params[configTemplateName]
+ Expect(ok).Should(BeTrue())
+ item.ConfigFileParams = deRef(tplParams)
+ result, err := ApplyParameters(item, cmObj, pdcr, pds)
+ Expect(err).Should(Succeed())
+ configReaders, err := cfgcore.LoadRawConfigObject(result.Data, configdesc.FileFormatConfig, []string{configdesc.Name})
+ Expect(err).Should(Succeed())
+ return configReaders[configdesc.Name]
+ }
+
+ Context("RerenderParametersTemplateTest", func() {
+ It("Render config with parameters", func() {
+ configMapObj := testparameters.NewComponentTemplateFactory(mysqlConfigName, testCtx.DefaultNamespace).
+ GetObject()
+
+ mockK8sCli.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult([]client.Object{
+ configMapObj,
+ }), testutil.WithAnyTimes()))
+
+ renderedObj := rerender(map[string]*string{
+ "max_connections": pointer.String("100"),
+ "read_buffer_size": pointer.String("55288"),
+ }, configMapObj, nil)
+ Expect(renderedObj).ShouldNot(BeNil())
+ Expect(renderedObj.Get("max_connections")).Should(BeEquivalentTo("100"))
+ Expect(renderedObj.Get("read_buffer_size")).Should(BeEquivalentTo("55288"))
+ })
+
+ It("Render config with custom template", func() {
+ configMapObj := testparameters.NewComponentTemplateFactory(mysqlConfigName, testCtx.DefaultNamespace).
+ GetObject()
+ customTemplate := testparameters.NewComponentTemplateFactory(mysqlConfigName, testCtx.DefaultNamespace).
+ AddConfigFile(testparameters.MysqlConfigFile, `
+[mysqld]
+innodb_buffer_pool_size=512M
+gtid_mode=OFF
+`).
+ GetObject()
+
+ mockK8sCli.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult([]client.Object{
+ configMapObj,
+ customTemplate,
+ }), testutil.WithAnyTimes()))
+
+ renderedObj := rerender(nil, nil, &appsv1.ConfigTemplateExtension{
+ TemplateRef: customTemplate.Name,
+ Namespace: testCtx.DefaultNamespace,
+ Policy: appsv1.ReplacePolicy,
+ })
+ Expect(renderedObj).ShouldNot(BeNil())
+ Expect(renderedObj.Get("innodb_buffer_pool_size")).Should(BeEquivalentTo("512M"))
+ Expect(renderedObj.Get("gtid_mode")).Should(BeEquivalentTo("OFF"))
+ Expect(renderedObj.Get("max_connections")).Should(BeNil())
+ })
+ })
+})
diff --git a/pkg/controller/configuration/template_validate.go b/pkg/controller/configuration/template_validate.go
new file mode 100644
index 00000000000..f1acf543df2
--- /dev/null
+++ b/pkg/controller/configuration/template_validate.go
@@ -0,0 +1,66 @@
+/*
+Copyright (C) 2022-2024 ApeCloud Co., Ltd
+
+This file is part of KubeBlocks project
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+*/
+
+package configuration
+
+import (
+ parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
+ "github.com/apecloud/kubeblocks/pkg/configuration/core"
+ "github.com/apecloud/kubeblocks/pkg/configuration/validate"
+)
+
+// validateRenderedData validates config file against constraint
+func validateRenderedData(renderedData map[string]string, paramsDefs []*parametersv1alpha1.ParametersDefinition, configRender *parametersv1alpha1.ParameterDrivenConfigRender) error {
+ if len(paramsDefs) == 0 || configRender == nil || len(configRender.Spec.Configs) == 0 {
+ return nil
+ }
+ for _, paramsDef := range paramsDefs {
+ fileName := paramsDef.Spec.FileName
+ if paramsDef.Spec.ParametersSchema == nil {
+ continue
+ }
+ if _, ok := renderedData[fileName]; !ok {
+ continue
+ }
+ if fileConfig := resolveFileFormatConfig(configRender.Spec.Configs, fileName); fileConfig != nil {
+ if err := validateConfigContent(renderedData[fileName], ¶msDef.Spec, fileConfig); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func resolveFileFormatConfig(configDescs []parametersv1alpha1.ComponentConfigDescription, fileName string) *parametersv1alpha1.FileFormatConfig {
+ for i, configDesc := range configDescs {
+ if fileName == configDesc.Name {
+ return configDescs[i].FileFormatConfig
+ }
+ }
+ return nil
+}
+
+func validateConfigContent(renderedData string, paramsDef *parametersv1alpha1.ParametersDefinitionSpec, fileFormat *parametersv1alpha1.FileFormatConfig) error {
+ configChecker := validate.NewConfigValidator(paramsDef.ParametersSchema, fileFormat)
+ // NOTE: It is necessary to verify the correctness of the data
+ if err := configChecker.Validate(renderedData); err != nil {
+ return core.WrapError(err, "failed to validate configmap")
+ }
+ return nil
+}
diff --git a/pkg/controller/configuration/template_wrapper.go b/pkg/controller/configuration/template_wrapper.go
deleted file mode 100644
index f2585a3e9e4..00000000000
--- a/pkg/controller/configuration/template_wrapper.go
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package configuration
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "reflect"
-
- corev1 "k8s.io/api/core/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- "github.com/apecloud/kubeblocks/pkg/configuration/core"
- cfgutil "github.com/apecloud/kubeblocks/pkg/configuration/util"
- "github.com/apecloud/kubeblocks/pkg/configuration/validate"
- "github.com/apecloud/kubeblocks/pkg/constant"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
- intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
- "github.com/apecloud/kubeblocks/pkg/generics"
-)
-
-type renderWrapper struct {
- render.TemplateRender
-
- volumes map[string]appsv1.ComponentTemplateSpec
- templateAnnotations map[string]string
- renderedObjs []*corev1.ConfigMap
-
- ctx context.Context
- cli client.Client
- cluster *appsv1.Cluster
- component *appsv1.Component
-}
-
-func newTemplateRenderWrapper(ctx context.Context, cli client.Client, templateBuilder render.TemplateRender,
- cluster *appsv1.Cluster, component *appsv1.Component) renderWrapper {
-
- return renderWrapper{
- ctx: ctx,
- cli: cli,
- cluster: cluster,
- component: component,
-
- TemplateRender: templateBuilder,
- templateAnnotations: make(map[string]string),
- volumes: make(map[string]appsv1.ComponentTemplateSpec),
- }
-}
-
-func (wrapper *renderWrapper) checkRerenderTemplateSpec(cfgCMName string, localObjs []client.Object) (*corev1.ConfigMap, error) {
- cmKey := client.ObjectKey{
- Name: cfgCMName,
- Namespace: wrapper.cluster.Namespace,
- }
-
- cmObj := &corev1.ConfigMap{}
- localObject := findMatchedLocalObject(localObjs, cmKey, generics.ToGVK(cmObj))
- if localObject != nil {
- if cm, ok := localObject.(*corev1.ConfigMap); ok {
- return cm, nil
- }
- }
-
- cmErr := wrapper.cli.Get(wrapper.ctx, cmKey, cmObj, inDataContext())
- if cmErr != nil && !apierrors.IsNotFound(cmErr) {
- // An unexpected error occurs
- return nil, cmErr
- }
- if cmErr != nil {
- // Config is not exists
- return nil, nil
- }
-
- return cmObj, nil
-}
-
-func (wrapper *renderWrapper) renderConfigTemplate(cluster *appsv1.Cluster,
- component *component.SynthesizedComponent,
- localObjs []client.Object,
- componentParameter *parametersv1alpha1.ComponentParameter,
- configRender *parametersv1alpha1.ParameterDrivenConfigRender,
- defs []*parametersv1alpha1.ParametersDefinition, revision string) error {
- for _, configSpec := range component.ConfigTemplates {
- var item *parametersv1alpha1.ConfigTemplateItemDetail
- cmName := core.GetComponentCfgName(cluster.Name, component.Name, configSpec.Name)
- origCMObj, err := wrapper.checkRerenderTemplateSpec(cmName, localObjs)
- if err != nil {
- return err
- }
- // If ConfigMap already exists, skip the rendering process.
- // In this way, the Component controller only creates ConfigMap objects for the first time,
- // and does not update the ConfigMap objects in the subsequent reconfiguration process.
- // The subsequent reconfiguration process is handled by the Configuration controller.
- if origCMObj != nil {
- wrapper.addVolumeMountMeta(configSpec, origCMObj, false)
- continue
- }
- item = intctrlutil.GetConfigTemplateItem(&componentParameter.Spec, configSpec.Name)
- if item == nil {
- return fmt.Errorf("config template item not found: %s", configSpec.Name)
- }
- newCMObj, err := wrapper.rerenderConfigTemplate(cluster, component, configSpec, item, configRender, defs)
- if err != nil {
- return err
- }
- if newCMObj, err = applyUpdatedParameters(item, newCMObj, configRender, defs); err != nil {
- return err
- }
- if err := wrapper.addRenderedObject(configSpec, newCMObj, componentParameter); err != nil {
- return err
- }
- if err := updateConfigMetaForCM(newCMObj, item, revision); err != nil {
- return err
- }
- }
- return nil
-}
-
-func updateConfigMetaForCM(newCMObj *corev1.ConfigMap, item *parametersv1alpha1.ConfigTemplateItemDetail, revision string) (err error) {
- if item == nil {
- return
- }
-
- annotations := newCMObj.GetAnnotations()
- if annotations == nil {
- annotations = make(map[string]string)
- }
- b, err := json.Marshal(item)
- if err != nil {
- return err
- }
- annotations[constant.ConfigAppliedVersionAnnotationKey] = string(b)
- hash, _ := cfgutil.ComputeHash(newCMObj.Data)
- annotations[constant.CMInsCurrentConfigurationHashLabelKey] = hash
- annotations[constant.ConfigurationRevision] = revision
- newCMObj.Annotations = annotations
- return
-}
-
-func applyUpdatedParameters(item *parametersv1alpha1.ConfigTemplateItemDetail, orig *corev1.ConfigMap, configRender *parametersv1alpha1.ParameterDrivenConfigRender, paramsDefs []*parametersv1alpha1.ParametersDefinition) (*corev1.ConfigMap, error) {
- if configRender == nil || len(configRender.Spec.Configs) == 0 {
- return nil, fmt.Errorf("not support parameter reconfigure")
- }
-
- newData, err := DoMerge(orig.Data, item.ConfigFileParams, paramsDefs, configRender.Spec.Configs)
- if err != nil {
- return nil, err
- }
-
- expected := orig.DeepCopy()
- expected.Data = newData
- return expected, nil
-}
-
-func (wrapper *renderWrapper) rerenderConfigTemplate(cluster *appsv1.Cluster,
- component *component.SynthesizedComponent,
- configSpec appsv1.ComponentTemplateSpec,
- item *parametersv1alpha1.ConfigTemplateItemDetail,
- configRender *parametersv1alpha1.ParameterDrivenConfigRender,
- defs []*parametersv1alpha1.ParametersDefinition) (*corev1.ConfigMap, error) {
- cmName := core.GetComponentCfgName(cluster.Name, component.Name, configSpec.Name)
- newCMObj, err := wrapper.RenderComponentTemplate(configSpec, cmName, func(m map[string]string) error {
- return validateRenderedData(m, defs, configRender)
- })
- if err != nil {
- return nil, err
- }
- // render user specified template
- if item != nil && item.CustomTemplates != nil {
- newData, err := mergerConfigTemplate(
- appsv1.ConfigTemplateExtension{
- TemplateRef: item.CustomTemplates.TemplateRef,
- Namespace: item.CustomTemplates.Namespace,
- Policy: item.CustomTemplates.Policy,
- },
- wrapper.TemplateRender,
- configSpec,
- newCMObj.Data,
- defs,
- configRender)
- if err != nil {
- return nil, err
- }
- newCMObj.Data = newData
- }
- UpdateCMConfigSpecLabels(newCMObj, configSpec)
- return newCMObj, nil
-}
-
-func (wrapper *renderWrapper) renderScriptTemplate(cluster *appsv1.Cluster, component *component.SynthesizedComponent,
- localObjs []client.Object, owner client.Object) error {
- for _, templateSpec := range component.ScriptTemplates {
- cmName := core.GetComponentCfgName(cluster.Name, component.Name, templateSpec.Name)
- object := findMatchedLocalObject(localObjs, client.ObjectKey{
- Name: cmName,
- Namespace: wrapper.cluster.Namespace}, generics.ToGVK(&corev1.ConfigMap{}))
- if object != nil {
- wrapper.addVolumeMountMeta(templateSpec, object.(*corev1.ConfigMap), false)
- continue
- }
-
- // Generate ConfigMap objects for config files
- cm, err := wrapper.RenderComponentTemplate(templateSpec, cmName, nil)
- if err != nil {
- return err
- }
- if err := wrapper.addRenderedObject(templateSpec, cm, owner); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (wrapper *renderWrapper) addRenderedObject(templateSpec appsv1.ComponentTemplateSpec, cm *corev1.ConfigMap, owner client.Object) (err error) {
- // The owner of the configmap object is a cluster,
- // in order to manage the life cycle of configmap
- if err = intctrlutil.SetControllerReference(owner, cm); err != nil {
- return err
- }
-
- core.SetParametersUpdateSource(cm, constant.ReconfigureManagerSource)
- wrapper.addVolumeMountMeta(templateSpec, cm, true)
- return nil
-}
-
-func (wrapper *renderWrapper) addVolumeMountMeta(templateSpec appsv1.ComponentTemplateSpec, object *corev1.ConfigMap, rendered bool) {
- wrapper.volumes[object.GetName()] = templateSpec
- if rendered {
- wrapper.renderedObjs = append(wrapper.renderedObjs, object)
- }
- wrapper.templateAnnotations[core.GenerateTPLUniqLabelKeyWithConfig(templateSpec.Name)] = object.GetName()
-}
-
-func (wrapper *renderWrapper) CheckAndPatchConfigResource(origCMObj *corev1.ConfigMap, newData map[string]string) error {
- if origCMObj == nil {
- return nil
- }
- if reflect.DeepEqual(origCMObj.Data, newData) {
- return nil
- }
-
- patch := client.MergeFrom(origCMObj.DeepCopy())
- origCMObj.Data = newData
- if origCMObj.Annotations == nil {
- origCMObj.Annotations = make(map[string]string)
- }
- core.SetParametersUpdateSource(origCMObj, constant.ReconfigureManagerSource)
- rawData, err := json.Marshal(origCMObj.Data)
- if err != nil {
- return err
- }
-
- origCMObj.Annotations[corev1.LastAppliedConfigAnnotation] = string(rawData)
- return wrapper.cli.Patch(wrapper.ctx, origCMObj, patch)
-}
-
-func findMatchedLocalObject(localObjs []client.Object, objKey client.ObjectKey, gvk schema.GroupVersionKind) client.Object {
- for _, obj := range localObjs {
- if obj.GetName() == objKey.Name && obj.GetNamespace() == objKey.Namespace {
- if generics.ToGVK(obj) == gvk {
- return obj
- }
- }
- }
- return nil
-}
-
-func UpdateCMConfigSpecLabels(cm *corev1.ConfigMap, configSpec appsv1.ComponentTemplateSpec) {
- if cm.Labels == nil {
- cm.Labels = make(map[string]string)
- }
- cm.Labels[constant.CMConfigurationSpecProviderLabelKey] = configSpec.Name
- cm.Labels[constant.CMConfigurationTemplateNameLabelKey] = configSpec.TemplateRef
-}
-
-// validateRenderedData validates config file against constraint
-func validateRenderedData(renderedData map[string]string, paramsDefs []*parametersv1alpha1.ParametersDefinition, configRender *parametersv1alpha1.ParameterDrivenConfigRender) error {
- if len(paramsDefs) == 0 || configRender == nil || len(configRender.Spec.Configs) == 0 {
- return nil
- }
- for _, paramsDef := range paramsDefs {
- fileName := paramsDef.Spec.FileName
- if paramsDef.Spec.ParametersSchema == nil {
- continue
- }
- if _, ok := renderedData[fileName]; !ok {
- continue
- }
- if fileConfig := resolveFileFormatConfig(configRender.Spec.Configs, fileName); fileConfig != nil {
- if err := validateConfigContent(renderedData[fileName], ¶msDef.Spec, fileConfig); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-func resolveFileFormatConfig(configDescs []parametersv1alpha1.ComponentConfigDescription, fileName string) *parametersv1alpha1.FileFormatConfig {
- for i, configDesc := range configDescs {
- if fileName == configDesc.Name {
- return configDescs[i].FileFormatConfig
- }
- }
- return nil
-}
-
-func validateConfigContent(renderedData string, paramsDef *parametersv1alpha1.ParametersDefinitionSpec, fileFormat *parametersv1alpha1.FileFormatConfig) error {
- configChecker := validate.NewConfigValidator(paramsDef.ParametersSchema, fileFormat)
- // NOTE: It is necessary to verify the correctness of the data
- if err := configChecker.Validate(renderedData); err != nil {
- return core.WrapError(err, "failed to validate configmap")
- }
- return nil
-}
diff --git a/pkg/controller/plan/prepare.go b/pkg/controller/plan/prepare.go
deleted file mode 100644
index 143ec886931..00000000000
--- a/pkg/controller/plan/prepare.go
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package plan
-
-import (
- corev1 "k8s.io/api/core/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/configuration"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
-)
-
-// RenderConfigNScriptFiles generates volumes for PodTemplate, volumeMount for container, rendered configTemplate and scriptTemplate,
-// and generates configManager sidecar for the reconfigure operation.
-func RenderConfigNScriptFiles(resourceCtx *render.ResourceCtx,
- cluster *appsv1.Cluster,
- component *appsv1.Component,
- synthesizedComponent *component.SynthesizedComponent,
- podSpec *corev1.PodSpec,
- localObjs []client.Object) error {
- return configuration.NewConfigReconcileTask(
- resourceCtx,
- cluster,
- component,
- synthesizedComponent,
- podSpec,
- localObjs).Reconcile()
-}
diff --git a/pkg/controller/plan/prepare_test.go b/pkg/controller/plan/prepare_test.go
deleted file mode 100644
index 07440023fea..00000000000
--- a/pkg/controller/plan/prepare_test.go
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-Copyright (C) 2022-2024 ApeCloud Co., Ltd
-
-This file is part of KubeBlocks project
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see .
-*/
-
-package plan
-
-import (
- . "github.com/onsi/ginkgo/v2"
- . "github.com/onsi/gomega"
-
- corev1 "k8s.io/api/core/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
-
- appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
- cfgcore "github.com/apecloud/kubeblocks/pkg/configuration/core"
- "github.com/apecloud/kubeblocks/pkg/controller/component"
- "github.com/apecloud/kubeblocks/pkg/controller/configuration"
- "github.com/apecloud/kubeblocks/pkg/controller/render"
- intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
- "github.com/apecloud/kubeblocks/pkg/generics"
- testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
- testparameters "github.com/apecloud/kubeblocks/pkg/testutil/parameters"
-)
-
-var _ = Describe("Prepare Test", func() {
- cleanEnv := func() {
- // must wait until resources deleted and no longer exist before the testcases start,
- // otherwise if later it needs to create some new resource objects with the same name,
- // in race conditions, it will find the existence of old objects, resulting failure to
- // create the new objects.
- By("clean resources")
-
- inNS := client.InNamespace(testCtx.DefaultNamespace)
- ml := client.HasLabels{testCtx.TestObjLabelKey}
-
- // non-namespaced
- testapps.ClearResources(&testCtx, generics.ParameterDrivenConfigRenderSignature, ml)
- testapps.ClearResources(&testCtx, generics.ParametersDefinitionSignature, ml)
- testapps.ClearResources(&testCtx, generics.ComponentDefinitionSignature, ml)
-
- // namespaced
- testapps.ClearResources(&testCtx, generics.ConfigMapSignature, inNS, ml)
- testapps.ClearResources(&testCtx, generics.ComponentSignature, inNS, ml)
- }
-
- BeforeEach(func() {
- cleanEnv()
- })
-
- AfterEach(func() {
- cleanEnv()
- })
-
- const (
- compDefName = "test-compdef"
- clusterName = "test-cluster"
- mysqlCompName = "mysql"
- paramsDefName = "mysql-params-def"
- pdcrName = "mysql-pdcr"
- envFileName = "test"
- )
-
- var (
- compDefObj *appsv1.ComponentDefinition
- cluster *appsv1.Cluster
- comp *appsv1.Component
- )
-
- Context("create cluster with component and component definition API, testing render configuration", func() {
- createAllTypesClusterDef := func() {
- By("Create a componentDefinition obj")
- compDefObj = testapps.NewComponentDefinitionFactory(compDefName).
- WithRandomName().
- SetDefaultSpec().
- AddConfigs(testapps.DefaultCompDefConfigs).
- AddScripts(testapps.DefaultCompDefScripts).
- AddVolumeMounts("mysql", []corev1.VolumeMount{{Name: testapps.DefaultConfigSpecVolumeName, MountPath: "/mnt/config"}}).
- Create(&testCtx).
- GetObject()
- Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(compDefObj), func(obj *appsv1.ComponentDefinition) {
- obj.Status.Phase = appsv1.AvailablePhase
- })()).Should(Succeed())
- }
-
- BeforeEach(func() {
- createAllTypesClusterDef()
-
- parametersDef := testparameters.NewParametersDefinitionFactory(paramsDefName).
- SetConfigFile(envFileName).
- Schema("").
- Create(&testCtx).
- GetObject()
- Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(parametersDef), func(obj *parametersv1alpha1.ParametersDefinition) {
- obj.Status.Phase = parametersv1alpha1.PDAvailablePhase
- })()).Should(Succeed())
-
- configRender := testparameters.NewParametersDrivenConfigFactory(pdcrName).
- SetConfigDescription(envFileName, testapps.DefaultConfigSpecName, parametersv1alpha1.FileFormatConfig{Format: parametersv1alpha1.Properties}).
- SetComponentDefinition(compDefObj.Name).
- SetParametersDefs(paramsDefName).
- Create(&testCtx).
- GetObject()
-
- Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(configRender), func(obj *parametersv1alpha1.ParameterDrivenConfigRender) {
- config := intctrlutil.GetComponentConfigDescription(&obj.Spec, envFileName)
- config.InjectEnvTo = []string{compDefObj.Spec.Runtime.Containers[0].Name}
- })()).Should(Succeed())
-
- Expect(testapps.GetAndChangeObjStatus(&testCtx, client.ObjectKeyFromObject(configRender), func(obj *parametersv1alpha1.ParameterDrivenConfigRender) {
- obj.Status.Phase = parametersv1alpha1.PDAvailablePhase
- })()).Should(Succeed())
-
- testparameters.NewComponentTemplateFactory(testapps.DefaultConfigSpecTplRef, testCtx.DefaultNamespace).
- AddConfigFile(envFileName, `
-dbStorage_rocksDB_writeBufferSizeMB=8
-dbStorage_rocksDB_sstSizeInMB=64
-dbStorage_rocksDB_blockSize=65536
-dbStorage_rocksDB_bloomFilterBitsPerKey=10
-dbStorage_rocksDB_numLevels=-1
-dbStorage_rocksDB_numFilesInLevel0=4
-dbStorage_rocksDB_maxSizeInLevel1MB=256
-`).
- Create(&testCtx)
-
- pvcSpec := testapps.NewPVCSpec("1Gi")
- cluster = testapps.NewClusterFactory(testCtx.DefaultNamespace, clusterName, "").
- AddComponent(mysqlCompName, compDefObj.Name).
- SetReplicas(1).
- AddVolumeClaimTemplate(testapps.DataVolumeName, pvcSpec).
- Create(&testCtx).
- GetObject()
-
- var err error
- comp, err = component.BuildComponent(cluster, &cluster.Spec.ComponentSpecs[0], nil, nil)
- Expect(err).Should(Succeed())
- comp.SetUID("test-uid")
- Expect(testCtx.CreateObj(ctx, comp)).Should(Succeed())
- })
-
- It("render configuration should success", func() {
- synthesizeComp, err := component.BuildSynthesizedComponent(ctx, testCtx.Cli, compDefObj, comp, cluster)
- Expect(err).Should(Succeed())
- Expect(synthesizeComp.PodSpec).ShouldNot(BeNil())
- resCtx := &render.ResourceCtx{
- Context: testCtx.Ctx,
- Client: testCtx.Cli,
- Namespace: synthesizeComp.Namespace,
- ClusterName: synthesizeComp.ClusterName,
- ComponentName: synthesizeComp.Name,
- }
- err = RenderConfigNScriptFiles(resCtx, cluster, comp, synthesizeComp, synthesizeComp.PodSpec, nil)
- Expect(err).Should(Succeed())
- Expect(configuration.CheckEnvFrom(&synthesizeComp.PodSpec.Containers[0], cfgcore.GenerateEnvFromName(cfgcore.GetComponentCfgName(cluster.Name, synthesizeComp.Name, testapps.DefaultConfigSpecName)))).Should(BeTrue())
- })
- })
-})
diff --git a/pkg/controllerutil/util.go b/pkg/controllerutil/util.go
index ebeb8717320..faa8dfab80f 100644
--- a/pkg/controllerutil/util.go
+++ b/pkg/controllerutil/util.go
@@ -79,7 +79,6 @@ func GetUncachedObjects() []client.Object {
&corev1.ConfigMap{},
&corev1.Secret{},
&appsv1.Cluster{},
- &appsv1alpha1.Configuration{},
}
}
diff --git a/pkg/generics/type.go b/pkg/generics/type.go
index e80350006de..4ae8a8ef4cc 100644
--- a/pkg/generics/type.go
+++ b/pkg/generics/type.go
@@ -30,8 +30,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
- appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
- appsv1beta1 "github.com/apecloud/kubeblocks/apis/apps/v1beta1"
dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1"
extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1"
opsv1alpha1 "github.com/apecloud/kubeblocks/apis/operations/v1alpha1"
@@ -105,11 +103,6 @@ var OpsDefinitionSignature = func(_ opsv1alpha1.OpsDefinition, _ *opsv1alpha1.Op
}
var OpsRequestSignature = func(_ opsv1alpha1.OpsRequest, _ *opsv1alpha1.OpsRequest, _ opsv1alpha1.OpsRequestList, _ *opsv1alpha1.OpsRequestList) {
}
-var ConfigConstraintSignature = func(_ appsv1beta1.ConfigConstraint, _ *appsv1beta1.ConfigConstraint, _ appsv1beta1.ConfigConstraintList, _ *appsv1beta1.ConfigConstraintList) {
-}
-var ConfigurationSignature = func(_ appsv1alpha1.Configuration, _ *appsv1alpha1.Configuration, _ appsv1alpha1.ConfigurationList, _ *appsv1alpha1.ConfigurationList) {
-}
-
var BackupPolicyTemplateSignature = func(_ dpv1alpha1.BackupPolicyTemplate, _ *dpv1alpha1.BackupPolicyTemplate, _ dpv1alpha1.BackupPolicyTemplateList, _ *dpv1alpha1.BackupPolicyTemplateList) {
}
var BackupPolicySignature = func(_ dpv1alpha1.BackupPolicy, _ *dpv1alpha1.BackupPolicy, _ dpv1alpha1.BackupPolicyList, _ *dpv1alpha1.BackupPolicyList) {
diff --git a/pkg/operations/reconfigure_test.go b/pkg/operations/reconfigure_test.go
index c8bb32641ec..220dcea364f 100644
--- a/pkg/operations/reconfigure_test.go
+++ b/pkg/operations/reconfigure_test.go
@@ -59,8 +59,6 @@ var _ = Describe("Reconfigure OpsRequest", func() {
// namespaced
testapps.ClearResources(&testCtx, generics.OpsRequestSignature, inNS, ml)
testapps.ClearResources(&testCtx, generics.ConfigMapSignature, inNS, ml)
- // non-namespaced
- testapps.ClearResources(&testCtx, generics.ConfigConstraintSignature, ml)
}
BeforeEach(cleanEnv)
diff --git a/test/testdata/config/config-constraint.yaml b/test/testdata/config/config-constraint.yaml
deleted file mode 100644
index 48452da60a5..00000000000
--- a/test/testdata/config/config-constraint.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-apiVersion: apps.kubeblocks.io/v1beta1
-kind: ConfigConstraint
-metadata:
- name: mysql-tree-node-template-8.0
- namespace: default
-spec:
- reloadAction:
- unixSignalTrigger:
- signal: SIGHUP
- processName: mysqld
-
-
- # ConfigurationSchema that impose restrictions on engine parameter's rule
- parametersSchema:
- # top level mysql configuration type
- topLevelKey: MysqlParameter
-
- # schema: auto generate from cue scripts
- # example: ../../pkg/configuration/testdata/mysql_openapi.json
- cue: |-
- [SectionName=_]: {
- // [OFF|ON] default ON
- automatic_sp_privileges: string & "OFF" | "ON" | *"ON"
- // [1~65535] default ON
- auto_increment_increment: int & >= 1 & <= 65535 | *1
- // [4096~16777216] default 2G
- binlog_stmt_cache_size?: int & >= 4096 & <= 16777216 | *2097152
- // [0|1|2] default: 2
- innodb_autoinc_lock_mode?: int & 0 | 1 | 2 | *2
- ...
- }
-
- # require db instance restart
- staticParameters:
- - automatic_sp_privileges
-
- # mysql configuration file format
- fileFormatConfig:
- format: ini
- iniConfig:
- sectionName: mysqld
\ No newline at end of file
diff --git a/test/testdata/config/config-template.yaml b/test/testdata/config/config-template.yaml
deleted file mode 100644
index 08774cf6231..00000000000
--- a/test/testdata/config/config-template.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: mysql-tree-node-template-8.0
- namespace: default
-data:
- my.cnf: |-
- [mysqld]
- innodb-buffer-pool-size=512M
- log-bin=master-bin
- gtid_mode=OFF
- consensus_auto_leader_transfer=ON
-
- pid-file=/var/run/mysqld/mysqld.pid
- socket=/var/run/mysqld/mysqld.sock
-
- port=3306
- general_log=0
- server-id=1
- slow_query_log=0
-
- [client]
- socket=/var/run/mysqld/mysqld.sock
- host=localhost
\ No newline at end of file
diff --git a/test/testdata/config/envfrom-config.yaml b/test/testdata/config/envfrom-config.yaml
deleted file mode 100644
index 9c2a56d51c4..00000000000
--- a/test/testdata/config/envfrom-config.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: env-from-config-tpl
- namespace: default
-data:
- env-config: |-
- dbStorage_rocksDB_writeBufferSizeMB=8
- dbStorage_rocksDB_sstSizeInMB=64
- dbStorage_rocksDB_blockSize=65536
- dbStorage_rocksDB_bloomFilterBitsPerKey=10
- dbStorage_rocksDB_numLevels=-1
- dbStorage_rocksDB_numFilesInLevel0=4
- dbStorage_rocksDB_maxSizeInLevel1MB=256
\ No newline at end of file
diff --git a/test/testdata/config/envfrom-constraint.yaml b/test/testdata/config/envfrom-constraint.yaml
deleted file mode 100644
index 1b215bf562d..00000000000
--- a/test/testdata/config/envfrom-constraint.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-apiVersion: apps.kubeblocks.io/v1beta1
-kind: ConfigConstraint
-metadata:
- name: env-from-config-test
-spec:
- fileFormatConfig:
- format: properties
\ No newline at end of file
diff --git a/test/testdata/operations_config/config-constraint.yaml b/test/testdata/operations_config/config-constraint.yaml
deleted file mode 100644
index bcd4b12e55f..00000000000
--- a/test/testdata/operations_config/config-constraint.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-apiVersion: apps.kubeblocks.io/v1beta1
-kind: ConfigConstraint
-metadata:
- name: mysql-tree-node-template-8.0
-spec:
- # ConfigurationSchema that impose restrictions on engine parameter's rule
- parametersSchema:
- # schema: auto generate from cue scripts
- # example: ../../pkg/configuration/testdata/mysql_openapi.json
- cue: |-
- #PARAM: {
- // [OFF|ON] default ON
- automatic_sp_privileges: string & "OFF" | "ON" | *"ON"
- // [1~65535] default ON
- auto_increment_increment: int & >= 1 & <= 65535 | *1
- // [4096~16777216] default 2G
- binlog_stmt_cache_size?: int & >= 4096 & <= 16777216 | *2097152
- // [0|1|2] default: 2
- innodb_autoinc_lock_mode?: int & 0 | 1 | 2 | *2
- ...
- }
- [SectionName=_]: #PARAM
-
- dynamicParameters:
- - binlog_stmt_cache_size
- - x
- - y
-
- # mysql configuration file format
- fileFormatConfig:
- format: ini
- iniConfig:
- sectionName: mysqld
\ No newline at end of file
diff --git a/test/testdata/operations_config/config-template.yaml b/test/testdata/operations_config/config-template.yaml
deleted file mode 100644
index 3f6bf005d83..00000000000
--- a/test/testdata/operations_config/config-template.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: mysql-tree-node-template-8.0
-data:
- my.cnf: |-
- [mysqld]
- innodb-buffer-pool-size=512M
- log-bin=master-bin
- gtid_mode=OFF
- consensus_auto_leader_transfer=ON
-
- pid-file=/var/run/mysqld/mysqld.pid
- socket=/var/run/mysqld/mysqld.sock
-
- port=3306
- general_log=0
- server-id=1
- slow_query_log=0
-
- [client]
- socket=/var/run/mysqld/mysqld.sock
- host=localhost
\ No newline at end of file