diff --git a/apis/apps/v1alpha1/cluster_types.go b/apis/apps/v1alpha1/cluster_types.go index 41fdaedd401..2ff053967b0 100644 --- a/apis/apps/v1alpha1/cluster_types.go +++ b/apis/apps/v1alpha1/cluster_types.go @@ -216,6 +216,9 @@ type ClusterStatus struct { } // ClusterComponentSpec defines the cluster component spec. +// +kubebuilder:validation:XValidation:rule="has(self.componentDefRef) || has(self.componentDef)",message="either componentDefRef or componentDef should be provided" +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.componentDefRef) || has(self.componentDefRef)", message="componentDefRef is required once set" +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.componentDef) || has(self.componentDef)", message="componentDef is required once set" type ClusterComponentSpec struct { // name defines cluster's component name, this name is also part of Service DNS name, so this name will // comply with IANA Service Naming rule. @@ -233,17 +236,11 @@ type ClusterComponentSpec struct { // +optional ComponentDefRef string `json:"componentDefRef"` - // enableComponentDefinition is the switch to control whether to enable the new ComponentDefinition API. - // ComponentDefinition and ClusterDefinition are mutually exclusive. When the switch is enabled, ComponentDefRef will be ignored. - // +kubebuilder:default=false - // +optional - EnableComponentDefinition bool `json:"enableComponentDefinition,omitempty"` - // componentDef references the name of the ComponentDefinition. - // When the enableComponentDefinition is true, ComponentDef must be provided. In this case, ComponentDef takes precedence over ComponentDefRef, and ComponentDefRef will be ignored. - // +kubebuilder:validation:Required + // If both componentDefRef and componentDef are provided, the componentDef will take precedence over componentDefRef. // +kubebuilder:validation:MaxLength=22 // +kubebuilder:validation:Pattern:=`^[a-z]([a-z0-9\-]*[a-z0-9])?$` + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="componentDef is immutable" // +optional ComponentDef string `json:"componentDef"` diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml index e196f205780..38987392fbd 100644 --- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml +++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml @@ -229,12 +229,14 @@ spec: type: object componentDef: description: componentDef references the name of the ComponentDefinition. - When the enableComponentDefinition is true, ComponentDef must - be provided. In this case, ComponentDef takes precedence over - ComponentDefRef, and ComponentDefRef will be ignored. + If both componentDefRef and componentDef are provided, the + componentDef will take precedence over componentDefRef. maxLength: 22 pattern: ^[a-z]([a-z0-9\-]*[a-z0-9])?$ type: string + x-kubernetes-validations: + - message: componentDef is immutable + rule: self == oldSelf componentDefRef: description: componentDefRef references componentDef defined in ClusterDefinition spec. Need to comply with IANA Service @@ -245,13 +247,6 @@ spec: x-kubernetes-validations: - message: componentDefRef is immutable rule: self == oldSelf - enableComponentDefinition: - default: false - description: enableComponentDefinition is the switch to control - whether to enable the new ComponentDefinition API. ComponentDefinition - and ClusterDefinition are mutually exclusive. When the switch - is enabled, ComponentDefRef will be ignored. - type: boolean enabledLogs: description: enabledLogs indicates which log file takes effect in the database cluster. element is the log type which is @@ -665,6 +660,13 @@ spec: - name - replicas type: object + x-kubernetes-validations: + - message: either componentDefRef or componentDef should be provided + rule: has(self.componentDefRef) || has(self.componentDef) + - message: componentDefRef is required once set + rule: '!has(oldSelf.componentDefRef) || has(self.componentDefRef)' + - message: componentDef is required once set + rule: '!has(oldSelf.componentDef) || has(self.componentDef)' maxItems: 128 minItems: 1 type: array diff --git a/controllers/apps/cluster_controller.go b/controllers/apps/cluster_controller.go index 831a00d78ed..738486eb76d 100644 --- a/controllers/apps/cluster_controller.go +++ b/controllers/apps/cluster_controller.go @@ -164,19 +164,14 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // TODO: transformers are vertices, theirs' dependencies are edges, make plan Build stage a DAG. plan, errBuild := planBuilder. AddTransformer( - // handle deletion // handle cluster deletion first &ClusterDeletionTransformer{}, // check is recovering from halted cluster &HaltRecoveryTransformer{}, - // assure meta-data info // update finalizer and cd&cv labels &AssureMetaTransformer{}, - // validate ref objects // validate cd & cv's existence and availability &ValidateAndLoadRefResourcesTransformer{}, - // validate config - &ValidateEnableLogsTransformer{}, // create cluster connection credential secret object &ClusterCredentialTransformer{Client: r.Client}, // handle restore before ClusterComponentTransformer diff --git a/controllers/apps/components/utils.go b/controllers/apps/components/utils.go index 8a967920e5d..76cc3ef1d8b 100644 --- a/controllers/apps/components/utils.go +++ b/controllers/apps/components/utils.go @@ -75,21 +75,6 @@ func ListPodOwnedByComponent(ctx context.Context, cli client.Client, namespace s return ListObjWithLabelsInNamespace(ctx, cli, generics.PodSignature, namespace, labels) } -// RestartPod restarts a Pod through updating the pod's annotation -func RestartPod(podTemplate *corev1.PodTemplateSpec) error { - if podTemplate.Annotations == nil { - podTemplate.Annotations = map[string]string{} - } - - startTimestamp := time.Now() // TODO(impl): opsRes.OpsRequest.Status.StartTimestamp - restartTimestamp := podTemplate.Annotations[constant.RestartAnnotationKey] - // if res, _ := time.Parse(time.RFC3339, restartTimestamp); startTimestamp.After(res) { - if res, _ := time.Parse(time.RFC3339, restartTimestamp); startTimestamp.Before(res) { - podTemplate.Annotations[constant.RestartAnnotationKey] = startTimestamp.Format(time.RFC3339) - } - return nil -} - // mergeAnnotations keeps the original annotations. // if annotations exist and are replaced, the Deployment/StatefulSet will be updated. func mergeAnnotations(originalAnnotations map[string]string, targetAnnotations *map[string]string) { diff --git a/controllers/apps/transformer_component_workload.go b/controllers/apps/transformer_component_workload.go index ff6376ad06a..dc7b0df48ed 100644 --- a/controllers/apps/transformer_component_workload.go +++ b/controllers/apps/transformer_component_workload.go @@ -153,11 +153,6 @@ func (t *ComponentWorkloadTransformer) handleWorkloadUpdate(reqCtx intctrlutil.R cluster *appsv1alpha1.Cluster, synthesizeComp *component.SynthesizedComponent, obj, rsm *workloads.ReplicatedStateMachine) error { cwo := newComponentWorkloadOps(reqCtx, t.Client, cluster, synthesizeComp, obj, rsm, dag) - // handle rsm workload restart - if err := cwo.restart(); err != nil { - return err - } - // handle rsm expand volume if err := cwo.expandVolume(); err != nil { return err @@ -295,11 +290,6 @@ func copyAndMerge(oldObj, newObj client.Object, cluster *appsv1alpha1.Cluster) c } } -// restart handles rsm workload restart by patch pod template annotation -func (r *componentWorkloadOps) restart() error { - return components.RestartPod(&r.runningRSM.Spec.Template) -} - // expandVolume handles rsm workload expand volume func (r *componentWorkloadOps) expandVolume() error { for _, vct := range r.runningRSM.Spec.VolumeClaimTemplates { diff --git a/controllers/apps/transformer_validate_enable_logs.go b/controllers/apps/transformer_validate_enable_logs.go deleted file mode 100644 index 94655b07f20..00000000000 --- a/controllers/apps/transformer_validate_enable_logs.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright (C) 2022-2023 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 ( - "github.com/apecloud/kubeblocks/pkg/controller/graph" -) - -// ValidateEnableLogsTransformer validates config and sends warning event log if necessary -type ValidateEnableLogsTransformer struct{} - -func (e *ValidateEnableLogsTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error { - transCtx, _ := ctx.(*clusterTransformContext) - cluster := transCtx.Cluster - - // validate config and send warning event log if necessary - err := cluster.Spec.ValidateEnabledLogs(transCtx.ClusterDef) - setProvisioningStartedCondition(&cluster.Status.Conditions, cluster.Name, cluster.Generation, err) - if err != nil { - return newRequeueError(requeueDuration, err.Error()) - } - - return nil -} - -var _ graph.Transformer = &ValidateEnableLogsTransformer{} diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml index e196f205780..38987392fbd 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml @@ -229,12 +229,14 @@ spec: type: object componentDef: description: componentDef references the name of the ComponentDefinition. - When the enableComponentDefinition is true, ComponentDef must - be provided. In this case, ComponentDef takes precedence over - ComponentDefRef, and ComponentDefRef will be ignored. + If both componentDefRef and componentDef are provided, the + componentDef will take precedence over componentDefRef. maxLength: 22 pattern: ^[a-z]([a-z0-9\-]*[a-z0-9])?$ type: string + x-kubernetes-validations: + - message: componentDef is immutable + rule: self == oldSelf componentDefRef: description: componentDefRef references componentDef defined in ClusterDefinition spec. Need to comply with IANA Service @@ -245,13 +247,6 @@ spec: x-kubernetes-validations: - message: componentDefRef is immutable rule: self == oldSelf - enableComponentDefinition: - default: false - description: enableComponentDefinition is the switch to control - whether to enable the new ComponentDefinition API. ComponentDefinition - and ClusterDefinition are mutually exclusive. When the switch - is enabled, ComponentDefRef will be ignored. - type: boolean enabledLogs: description: enabledLogs indicates which log file takes effect in the database cluster. element is the log type which is @@ -665,6 +660,13 @@ spec: - name - replicas type: object + x-kubernetes-validations: + - message: either componentDefRef or componentDef should be provided + rule: has(self.componentDefRef) || has(self.componentDef) + - message: componentDefRef is required once set + rule: '!has(oldSelf.componentDefRef) || has(self.componentDefRef)' + - message: componentDef is required once set + rule: '!has(oldSelf.componentDef) || has(self.componentDef)' maxItems: 128 minItems: 1 type: array diff --git a/pkg/controller/component/component.go b/pkg/controller/component/component.go index c5dbdd204ac..42441b0cbfc 100644 --- a/pkg/controller/component/component.go +++ b/pkg/controller/component/component.go @@ -36,17 +36,18 @@ func BuildProtoComponent(reqCtx ictrlutil.RequestCtx, cli client.Client, cluster *appsv1alpha1.Cluster, clusterCompSpec *appsv1alpha1.ClusterComponentSpec) (*appsv1alpha1.Component, error) { - // check if clusterCompSpec enable the ComponentDefinition API feature gate. - if clusterCompSpec.EnableComponentDefinition && clusterCompSpec.ComponentDef != "" { - return buildProtoCompFromCompDef(reqCtx, cli, cluster, clusterCompSpec) - } - if !clusterCompSpec.EnableComponentDefinition && clusterCompSpec.ComponentDefRef != "" { + if clusterCompSpec.ComponentDef == "" { + if clusterCompSpec.ComponentDefRef == "" { + return nil, errors.New("invalid component spec") + } if cluster.Spec.ClusterDefRef == "" { - return nil, errors.New("clusterDefRef is required when enableComponentDefinition is false") + return nil, errors.New("clusterDefRef is required when component def is not provided") } - return buildProtoCompFromConvertor(reqCtx, cli, cluster, clusterCompSpec) } - return nil, errors.New("invalid component spec") + if clusterCompSpec.ComponentDef != "" { + return buildProtoCompFromCompDef(reqCtx, cli, cluster, clusterCompSpec) + } + return buildProtoCompFromConvertor(reqCtx, cli, cluster, clusterCompSpec) } // BuildComponentDefinition constructs a ComponentDefinition object based on the following rules: @@ -56,21 +57,22 @@ func BuildComponentDefinition(reqCtx ictrlutil.RequestCtx, cli client.Client, cluster *appsv1alpha1.Cluster, clusterCompSpec *appsv1alpha1.ClusterComponentSpec) (*appsv1alpha1.ComponentDefinition, error) { - // check if clusterCompSpec enable the ComponentDefinition API feature gate. - if clusterCompSpec.EnableComponentDefinition && clusterCompSpec.ComponentDef != "" { + if clusterCompSpec.ComponentDef == "" { + if clusterCompSpec.ComponentDefRef == "" { + return nil, errors.New("invalid component spec") + } + if cluster.Spec.ClusterDefRef == "" { + return nil, errors.New("clusterDefRef is required when component def is not provided") + } + } + if clusterCompSpec.ComponentDef != "" { cmpd := &appsv1alpha1.ComponentDefinition{} if err := ictrlutil.ValidateExistence(reqCtx.Ctx, cli, types.NamespacedName{Name: clusterCompSpec.ComponentDef}, cmpd, false); err != nil { return nil, err } return cmpd, nil } - if !clusterCompSpec.EnableComponentDefinition && clusterCompSpec.ComponentDefRef != "" { - if cluster.Spec.ClusterDefRef == "" { - return nil, errors.New("clusterDefRef is required when enableComponentDefinition is false") - } - return buildCompDefFromConvertor(reqCtx, cli, cluster, clusterCompSpec) - } - return nil, errors.New("invalid component spec") + return buildCompDefFromConvertor(reqCtx, cli, cluster, clusterCompSpec) } // buildCompDefFromConvertor builds a new ComponentDefinition object based on converting clusterComponentDefinition to ComponentDefinition.