diff --git a/controllers/apps/componentdefinition_controller.go b/controllers/apps/componentdefinition_controller.go index 3d77e07e22b..0898cf2c03d 100644 --- a/controllers/apps/componentdefinition_controller.go +++ b/controllers/apps/componentdefinition_controller.go @@ -35,6 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + appsconfig "github.com/apecloud/kubeblocks/controllers/apps/configuration" "github.com/apecloud/kubeblocks/pkg/constant" intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil" ) @@ -46,9 +47,9 @@ type ComponentDefinitionReconciler struct { Recorder record.EventRecorder } -//+kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions/finalizers,verbs=update +// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=componentdefinitions/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. @@ -153,7 +154,6 @@ func (r *ComponentDefinitionReconciler) validate(cli client.Client, rctx intctrl r.validateHostNetwork, r.validateServices, r.validateConfigs, - r.validateScripts, r.validatePolicyRules, r.validateLabels, r.validateReplicasLimit, @@ -268,16 +268,8 @@ func (r *ComponentDefinitionReconciler) validateServices(cli client.Client, rctx } func (r *ComponentDefinitionReconciler) validateConfigs(cli client.Client, rctx intctrlutil.RequestCtx, - cmpd *appsv1alpha1.ComponentDefinition) error { - // if err := appsconfig.ReconcileConfigSpecsForReferencedCR(r.Client, rctx, dbClusterDef); err != nil { - // return intctrlutil.RequeueAfter(time.Second, reqCtx.Log, err.Error()) - // } - return nil -} - -func (r *ComponentDefinitionReconciler) validateScripts(cli client.Client, rctx intctrlutil.RequestCtx, - cmpd *appsv1alpha1.ComponentDefinition) error { - return nil + compDef *appsv1alpha1.ComponentDefinition) error { + return appsconfig.ReconcileConfigSpecsForReferencedCR(cli, rctx, compDef) } func (r *ComponentDefinitionReconciler) validatePolicyRules(cli client.Client, rctx intctrlutil.RequestCtx, diff --git a/controllers/apps/configuration/config_util.go b/controllers/apps/configuration/config_util.go index 73dc4e56b26..b540ded9541 100644 --- a/controllers/apps/configuration/config_util.go +++ b/controllers/apps/configuration/config_util.go @@ -38,6 +38,7 @@ import ( "github.com/apecloud/kubeblocks/pkg/configuration/openapi" "github.com/apecloud/kubeblocks/pkg/configuration/validate" "github.com/apecloud/kubeblocks/pkg/constant" + "github.com/apecloud/kubeblocks/pkg/controller/configuration" intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil" "github.com/apecloud/kubeblocks/pkg/generics" ) @@ -159,7 +160,7 @@ func batchDeleteConfigMapFinalizer(cli client.Client, ctx intctrlutil.RequestCtx labels := client.MatchingLabels{ core.GenerateTPLUniqLabelKeyWithConfig(configSpec.Name): configSpec.TemplateRef, } - if ok, err := validateConfigMapOwners(cli, ctx, labels, validator, &appsv1alpha1.ClusterVersionList{}, &appsv1alpha1.ClusterDefinitionList{}); err != nil { + if ok, err := validateConfigMapOwners(cli, ctx, labels, validator, &appsv1alpha1.ClusterVersionList{}, &appsv1alpha1.ClusterDefinitionList{}, &appsv1alpha1.ComponentDefinitionList{}); err != nil { return err } else if !ok { continue @@ -245,6 +246,8 @@ func handleConfigTemplate(object client.Object, handler ConfigTemplateHandler, h configTemplates, err = getConfigTemplateFromCD(cr, handler2...) case *appsv1alpha1.ClusterVersion: configTemplates = getConfigTemplateFromCV(cr) + case *appsv1alpha1.ComponentDefinition: + configTemplates = getConfigTemplateFromComponentDef(cr) default: return false, core.MakeError("not support CR type: %v", cr) } @@ -293,6 +296,19 @@ func getConfigTemplateFromCD(clusterDef *appsv1alpha1.ClusterDefinition, validat return configTemplates, nil } +func getConfigTemplateFromComponentDef(componentDef *appsv1alpha1.ComponentDefinition) []appsv1alpha1.ComponentConfigSpec { + configTemplates := make([]appsv1alpha1.ComponentConfigSpec, 0) + // For compatibility with the previous lifecycle management of configurationSpec.TemplateRef, + // it is necessary to convert ScriptSpecs to ConfigSpecs, + // ensuring that the script-related configmap is not allowed to be deleted. + for _, scriptSpec := range componentDef.Spec.Scripts { + configTemplates = append(configTemplates, appsv1alpha1.ComponentConfigSpec{ + ComponentTemplateSpec: scriptSpec, + }) + } + return append(configTemplates, componentDef.Spec.Configs...) +} + func checkConfigTemplate(client client.Client, ctx intctrlutil.RequestCtx, obj client.Object) (bool, error) { handler := func(configSpecs []appsv1alpha1.ComponentConfigSpec) (bool, error) { return validateConfigTemplate(client, ctx, configSpecs) @@ -303,17 +319,7 @@ func checkConfigTemplate(client client.Client, ctx intctrlutil.RequestCtx, obj c func updateLabelsByConfigSpec[T generics.Object, PT generics.PObject[T]](cli client.Client, ctx intctrlutil.RequestCtx, obj PT) (bool, error) { handler := func(configSpecs []appsv1alpha1.ComponentConfigSpec) (bool, error) { patch := client.MergeFrom(PT(obj.DeepCopy())) - labels := obj.GetLabels() - if labels == nil { - labels = map[string]string{} - } - for _, configSpec := range configSpecs { - labels[core.GenerateTPLUniqLabelKeyWithConfig(configSpec.Name)] = configSpec.TemplateRef - if len(configSpec.ConfigConstraintRef) != 0 { - labels[core.GenerateConstraintsUniqLabelKeyWithConfig(configSpec.ConfigConstraintRef)] = configSpec.ConfigConstraintRef - } - } - obj.SetLabels(labels) + configuration.BuildConfigConstraintLabels(obj, configSpecs) return true, cli.Patch(ctx.Ctx, obj, patch) } return handleConfigTemplate(obj, handler) diff --git a/controllers/apps/transformer_component_workload.go b/controllers/apps/transformer_component_workload.go index 430b2c30ca9..88724fb0538 100644 --- a/controllers/apps/transformer_component_workload.go +++ b/controllers/apps/transformer_component_workload.go @@ -38,10 +38,9 @@ import ( appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" workloads "github.com/apecloud/kubeblocks/apis/workloads/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" + "github.com/apecloud/kubeblocks/pkg/controller/configuration" "github.com/apecloud/kubeblocks/pkg/controller/factory" "github.com/apecloud/kubeblocks/pkg/controller/graph" "github.com/apecloud/kubeblocks/pkg/controller/model" @@ -110,7 +109,7 @@ func (t *componentWorkloadTransformer) Transform(ctx graph.TransformContext, dag buildInstanceSetPlacementAnnotation(transCtx.Component, protoITS) // build configuration template annotations to workload - buildInstanceSetConfigTplAnnotations(protoITS, synthesizeComp) + configuration.BuildConfigTemplateAnnotations(protoITS, synthesizeComp) graphCli, _ := transCtx.Client.(model.GraphClient) if runningITS == nil { @@ -913,43 +912,6 @@ func buildInstanceSetPlacementAnnotation(comp *appsv1alpha1.Component, its *work its.Annotations[constant.KBAppMultiClusterPlacementKey] = placement(comp) } -// buildInstanceSetConfigTplAnnotations builds config tpl annotations for ITS -func buildInstanceSetConfigTplAnnotations(its *workloads.InstanceSet, synthesizedComp *component.SynthesizedComponent) { - configTplAnnotations := make(map[string]string) - for _, configTplSpec := range synthesizedComp.ConfigTemplates { - configTplAnnotations[core.GenerateTPLUniqLabelKeyWithConfig(configTplSpec.Name)] = core.GetComponentCfgName(synthesizedComp.ClusterName, synthesizedComp.Name, configTplSpec.Name) - } - for _, scriptTplSpec := range synthesizedComp.ScriptTemplates { - configTplAnnotations[core.GenerateTPLUniqLabelKeyWithConfig(scriptTplSpec.Name)] = core.GetComponentCfgName(synthesizedComp.ClusterName, synthesizedComp.Name, scriptTplSpec.Name) - } - updateInstanceSetAnnotationsWithTemplate(its, configTplAnnotations) -} - -func updateInstanceSetAnnotationsWithTemplate(its *workloads.InstanceSet, allTemplateAnnotations map[string]string) { - // full configmap upgrade - existLabels := make(map[string]string) - annotations := its.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - for key, val := range annotations { - if strings.HasPrefix(key, constant.ConfigurationTplLabelPrefixKey) { - existLabels[key] = val - } - } - - // delete not exist configmap label - deletedLabels := cfgutil.MapKeyDifference(existLabels, allTemplateAnnotations) - for l := range deletedLabels.Iter() { - delete(annotations, l) - } - - for key, val := range allTemplateAnnotations { - annotations[key] = val - } - its.SetAnnotations(annotations) -} - func newComponentWorkloadOps(reqCtx intctrlutil.RequestCtx, cli client.Client, cluster *appsv1alpha1.Cluster, diff --git a/pkg/controller/configuration/annotation_utils.go b/pkg/controller/configuration/annotation_utils.go new file mode 100644 index 00000000000..067a4536f5c --- /dev/null +++ b/pkg/controller/configuration/annotation_utils.go @@ -0,0 +1,82 @@ +/* +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 ( + "strings" + + "sigs.k8s.io/controller-runtime/pkg/client" + + appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/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" +) + +// BuildConfigConstraintLabels builds config constraints labels for object +func BuildConfigConstraintLabels(object client.Object, configSpecs []appsv1alpha1.ComponentConfigSpec) { + asMapLabels := make(map[string]string) + for _, configSpec := range configSpecs { + asMapLabels[core.GenerateTPLUniqLabelKeyWithConfig(configSpec.Name)] = configSpec.TemplateRef + if len(configSpec.ConfigConstraintRef) != 0 { + asMapLabels[core.GenerateConstraintsUniqLabelKeyWithConfig(configSpec.ConfigConstraintRef)] = configSpec.ConfigConstraintRef + } + } + updateLabelsOrAnnotations(asMapLabels, object.GetLabels, object.SetLabels, constant.ConfigurationConstraintsLabelPrefixKey, constant.ConfigurationTplLabelPrefixKey) +} + +// BuildConfigTemplateAnnotations builds config template annotations for object +func BuildConfigTemplateAnnotations(object client.Object, synthesizedComp *component.SynthesizedComponent) { + asMapAnnotations := make(map[string]string) + for _, configTplSpec := range synthesizedComp.ConfigTemplates { + asMapAnnotations[core.GenerateTPLUniqLabelKeyWithConfig(configTplSpec.Name)] = core.GetComponentCfgName(synthesizedComp.ClusterName, synthesizedComp.Name, configTplSpec.Name) + } + for _, scriptTplSpec := range synthesizedComp.ScriptTemplates { + asMapAnnotations[core.GenerateTPLUniqLabelKeyWithConfig(scriptTplSpec.Name)] = core.GetComponentCfgName(synthesizedComp.ClusterName, synthesizedComp.Name, scriptTplSpec.Name) + } + updateLabelsOrAnnotations(asMapAnnotations, object.GetAnnotations, object.SetAnnotations, constant.ConfigurationTplLabelPrefixKey) +} + +func updateLabelsOrAnnotations(newLabels map[string]string, getter func() map[string]string, setter func(map[string]string), labelPrefix ...string) { + existLabels := make(map[string]string) + updatedLabels := getter() + if updatedLabels == nil { + updatedLabels = make(map[string]string) + } + + for key, val := range updatedLabels { + matchLabel: + for _, prefix := range labelPrefix { + if strings.HasPrefix(key, prefix) { + existLabels[key] = val + break matchLabel + } + } + } + + // delete not exist configmap label + deletedLabels := cfgutil.MapKeyDifference(existLabels, newLabels) + for l := range deletedLabels.Iter() { + delete(updatedLabels, l) + } + + for key, val := range newLabels { + updatedLabels[key] = val + } + setter(updatedLabels) +}