Skip to content

Commit fb30697

Browse files
authored
chore: require KB labels for external-managed ConfigMaps (#10332)
1 parent 596bebd commit fb30697

15 files changed

Lines changed: 471 additions & 48 deletions

apis/apps/v1/componentdefinition_types.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,8 +1098,11 @@ type ComponentFileTemplate struct {
10981098
// +optional
10991099
DefaultMode *int32 `json:"defaultMode,omitempty"`
11001100

1101-
// ExternalManaged indicates whether the configuration is managed by an external system.
1102-
// When set to true, the controller will ignore the management of this configuration.
1101+
// ExternalManaged specifies whether the file management is delegated to an external system.
1102+
//
1103+
// When set to true, the apps controller will ignore the rendering and lifecycle management of
1104+
// this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
1105+
// carries the common KubeBlocks component labels.
11031106
//
11041107
// +optional
11051108
ExternalManaged *bool `json:"externalManaged,omitempty"`

apis/apps/v1/types.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,12 @@ type ClusterComponentConfig struct {
536536
// +optional
537537
Reconfigure *Action `json:"reconfigure,omitempty"`
538538

539-
// ExternalManaged indicates whether the configuration is managed by an external system.
540-
// When set to true, the controller will use the user-provided template and reconfigure action,
541-
// ignoring the default template and update behavior.
539+
// ExternalManaged specifies whether the configuration management is delegated to an external system.
540+
//
541+
// When set to true, the apps controller does not render or manage the configuration from the
542+
// default templates and update behaviors specified in the ComponentDefinition. A ConfigMap source
543+
// for an external-managed configuration is accepted only when the referenced ConfigMap carries
544+
// the common KubeBlocks component labels.
542545
//
543546
// +optional
544547
ExternalManaged *bool `json:"externalManaged,omitempty"`

config/crd/bases/apps.kubeblocks.io_clusters.yaml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,12 @@ spec:
266266
x-kubernetes-map-type: atomic
267267
externalManaged:
268268
description: |-
269-
ExternalManaged indicates whether the configuration is managed by an external system.
270-
When set to true, the controller will use the user-provided template and reconfigure action,
271-
ignoring the default template and update behavior.
269+
ExternalManaged specifies whether the configuration management is delegated to an external system.
270+
271+
When set to true, the apps controller does not render or manage the configuration from the
272+
default templates and update behaviors specified in the ComponentDefinition. A ConfigMap source
273+
for an external-managed configuration is accepted only when the referenced ConfigMap carries
274+
the common KubeBlocks component labels.
272275
type: boolean
273276
name:
274277
description: The name of the config.
@@ -7609,9 +7612,12 @@ spec:
76097612
x-kubernetes-map-type: atomic
76107613
externalManaged:
76117614
description: |-
7612-
ExternalManaged indicates whether the configuration is managed by an external system.
7613-
When set to true, the controller will use the user-provided template and reconfigure action,
7614-
ignoring the default template and update behavior.
7615+
ExternalManaged specifies whether the configuration management is delegated to an external system.
7616+
7617+
When set to true, the apps controller does not render or manage the configuration from the
7618+
default templates and update behaviors specified in the ComponentDefinition. A ConfigMap source
7619+
for an external-managed configuration is accepted only when the referenced ConfigMap carries
7620+
the common KubeBlocks component labels.
76157621
type: boolean
76167622
name:
76177623
description: The name of the config.

config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3710,8 +3710,11 @@ spec:
37103710
type: integer
37113711
externalManaged:
37123712
description: |-
3713-
ExternalManaged indicates whether the configuration is managed by an external system.
3714-
When set to true, the controller will ignore the management of this configuration.
3713+
ExternalManaged specifies whether the file management is delegated to an external system.
3714+
3715+
When set to true, the apps controller will ignore the rendering and lifecycle management of
3716+
this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
3717+
carries the common KubeBlocks component labels.
37153718
type: boolean
37163719
name:
37173720
description: Specifies the name of the template.
@@ -16985,8 +16988,11 @@ spec:
1698516988
type: integer
1698616989
externalManaged:
1698716990
description: |-
16988-
ExternalManaged indicates whether the configuration is managed by an external system.
16989-
When set to true, the controller will ignore the management of this configuration.
16991+
ExternalManaged specifies whether the file management is delegated to an external system.
16992+
16993+
When set to true, the apps controller will ignore the rendering and lifecycle management of
16994+
this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
16995+
carries the common KubeBlocks component labels.
1699016996
type: boolean
1699116997
name:
1699216998
description: Specifies the name of the template.

config/crd/bases/apps.kubeblocks.io_components.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,12 @@ spec:
152152
x-kubernetes-map-type: atomic
153153
externalManaged:
154154
description: |-
155-
ExternalManaged indicates whether the configuration is managed by an external system.
156-
When set to true, the controller will use the user-provided template and reconfigure action,
157-
ignoring the default template and update behavior.
155+
ExternalManaged specifies whether the configuration management is delegated to an external system.
156+
157+
When set to true, the apps controller does not render or manage the configuration from the
158+
default templates and update behaviors specified in the ComponentDefinition. A ConfigMap source
159+
for an external-managed configuration is accepted only when the referenced ConfigMap carries
160+
the common KubeBlocks component labels.
158161
type: boolean
159162
name:
160163
description: The name of the config.

config/crd/bases/apps.kubeblocks.io_sidecardefinitions.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,11 @@ spec:
8585
type: integer
8686
externalManaged:
8787
description: |-
88-
ExternalManaged indicates whether the configuration is managed by an external system.
89-
When set to true, the controller will ignore the management of this configuration.
88+
ExternalManaged specifies whether the file management is delegated to an external system.
89+
90+
When set to true, the apps controller will ignore the rendering and lifecycle management of
91+
this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
92+
carries the common KubeBlocks component labels.
9093
type: boolean
9194
name:
9295
description: Specifies the name of the template.
@@ -1492,8 +1495,11 @@ spec:
14921495
type: integer
14931496
externalManaged:
14941497
description: |-
1495-
ExternalManaged indicates whether the configuration is managed by an external system.
1496-
When set to true, the controller will ignore the management of this configuration.
1498+
ExternalManaged specifies whether the file management is delegated to an external system.
1499+
1500+
When set to true, the apps controller will ignore the rendering and lifecycle management of
1501+
this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
1502+
carries the common KubeBlocks component labels.
14971503
type: boolean
14981504
name:
14991505
description: Specifies the name of the template.

config/crd/bases/parameters.kubeblocks.io_componentparameters.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ spec:
141141
type: integer
142142
externalManaged:
143143
description: |-
144-
ExternalManaged indicates whether the configuration is managed by an external system.
145-
When set to true, the controller will ignore the management of this configuration.
144+
ExternalManaged specifies whether the file management is delegated to an external system.
145+
146+
When set to true, the apps controller will ignore the rendering and lifecycle management of
147+
this file. A ConfigMap source for this template is accepted only when the referenced ConfigMap
148+
carries the common KubeBlocks component labels.
146149
type: boolean
147150
name:
148151
description: Specifies the name of the template.

controllers/apps/component/transformer_component_validation.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,16 @@ package component
2222
import (
2323
"fmt"
2424

25+
corev1 "k8s.io/api/core/v1"
26+
apierrors "k8s.io/apimachinery/pkg/api/errors"
27+
"k8s.io/apimachinery/pkg/types"
28+
"k8s.io/utils/ptr"
29+
2530
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
31+
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
2632
appsutil "github.com/apecloud/kubeblocks/controllers/apps/util"
33+
"github.com/apecloud/kubeblocks/pkg/constant"
34+
"github.com/apecloud/kubeblocks/pkg/controller/component"
2735
"github.com/apecloud/kubeblocks/pkg/controller/graph"
2836
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
2937
)
@@ -52,6 +60,9 @@ func (t *componentValidationTransformer) Transform(ctx graph.TransformContext, d
5260
if err = validateCompReplicas(comp, transCtx.CompDef); err != nil {
5361
return intctrlutil.NewRequeueError(appsutil.RequeueDuration, err.Error())
5462
}
63+
if err = validateExternalManagedConfigSources(transCtx); err != nil {
64+
return intctrlutil.NewRequeueError(appsutil.RequeueDuration, err.Error())
65+
}
5566
// if err = validateSidecarContainers(comp, transCtx.CompDef); err != nil {
5667
// return newRequeueError(requeueDuration, err.Error())
5768
// }
@@ -75,3 +86,103 @@ func validateCompReplicas(comp *appsv1.Component, compDef *appsv1.ComponentDefin
7586
func replicasOutOfLimitError(replicas int32, replicasLimit appsv1.ReplicasLimit) error {
7687
return fmt.Errorf("replicas %d out-of-limit [%d, %d]", replicas, replicasLimit.MinReplicas, replicasLimit.MaxReplicas)
7788
}
89+
90+
func validateExternalManagedConfigSources(transCtx *componentTransformContext) error {
91+
comp := transCtx.Component
92+
if len(comp.Spec.Configs) == 0 {
93+
return nil
94+
}
95+
96+
externalManagedTemplates := map[string]component.SynthesizedFileTemplate{}
97+
for _, tpl := range transCtx.SynthesizeComponent.FileTemplates {
98+
if tpl.Config && ptr.Deref(tpl.ExternalManaged, false) {
99+
externalManagedTemplates[tpl.Name] = tpl
100+
}
101+
}
102+
103+
var externalManagedConfigs []appsv1.ClusterComponentConfig
104+
externalManagedConfigTemplates := map[string]component.SynthesizedFileTemplate{}
105+
for _, config := range comp.Spec.Configs {
106+
if config.Name == nil || config.ConfigMap == nil || config.ConfigMap.Name == "" {
107+
continue
108+
}
109+
tpl, externalManagedTemplate := externalManagedTemplates[*config.Name]
110+
if !externalManagedTemplate && !ptr.Deref(config.ExternalManaged, false) {
111+
continue
112+
}
113+
externalManagedConfigs = append(externalManagedConfigs, config)
114+
if externalManagedTemplate {
115+
externalManagedConfigTemplates[*config.Name] = tpl
116+
}
117+
}
118+
if len(externalManagedConfigs) == 0 {
119+
return nil
120+
}
121+
122+
clusterName, err := component.GetClusterName(comp)
123+
if err != nil {
124+
return err
125+
}
126+
compName, err := component.ShortName(clusterName, comp.Name)
127+
if err != nil {
128+
return err
129+
}
130+
131+
for _, config := range externalManagedConfigs {
132+
tpl := externalManagedConfigTemplates[*config.Name]
133+
if isExistingExternalManagedConfigSource(transCtx, config, tpl) {
134+
continue
135+
}
136+
if err := validateManagedConfigMapLabels(transCtx, config.ConfigMap.Name, clusterName, compName); err != nil {
137+
return err
138+
}
139+
}
140+
return nil
141+
}
142+
143+
func isExistingExternalManagedConfigSource(transCtx *componentTransformContext, config appsv1.ClusterComponentConfig, tpl component.SynthesizedFileTemplate) bool {
144+
if transCtx.RunningWorkload == nil || config.ConfigMap == nil || tpl.VolumeName == "" {
145+
return false
146+
}
147+
runningITS, ok := transCtx.RunningWorkload.(*workloads.InstanceSet)
148+
if !ok || runningITS == nil {
149+
return false
150+
}
151+
for _, volume := range runningITS.Spec.Template.Spec.Volumes {
152+
if volume.Name == tpl.VolumeName && volume.ConfigMap != nil && volume.ConfigMap.Name == config.ConfigMap.Name {
153+
return true
154+
}
155+
}
156+
return false
157+
}
158+
159+
func validateManagedConfigMapLabels(transCtx *componentTransformContext, cmName, clusterName, compName string) error {
160+
cm := &corev1.ConfigMap{}
161+
cmKey := types.NamespacedName{
162+
Namespace: transCtx.Component.Namespace,
163+
Name: cmName,
164+
}
165+
if err := transCtx.Client.Get(transCtx.Context, cmKey, cm); err != nil {
166+
if apierrors.IsNotFound(err) {
167+
return fmt.Errorf("configMap %q for external-managed config is not found", cmName)
168+
}
169+
return err
170+
}
171+
172+
// Treat these common component labels as the apps-level handoff contract for
173+
// externally managed config sources. The component controller intentionally
174+
// does not inspect parameters-specific names, annotations, finalizers, or
175+
// owner references.
176+
expectedLabels := map[string]string{
177+
constant.AppManagedByLabelKey: constant.AppName,
178+
constant.AppInstanceLabelKey: clusterName,
179+
constant.KBAppComponentLabelKey: compName,
180+
}
181+
for key, expected := range expectedLabels {
182+
if actual := cm.Labels[key]; actual != expected {
183+
return fmt.Errorf("configMap %q for external-managed config must have label %q=%q, got %q",
184+
cmName, key, expected, actual)
185+
}
186+
}
187+
return nil
188+
}

0 commit comments

Comments
 (0)