diff --git a/controllers/apps/cluster_controller.go b/controllers/apps/cluster_controller.go
index f8a39d52993..011771ad7dc 100644
--- a/controllers/apps/cluster_controller.go
+++ b/controllers/apps/cluster_controller.go
@@ -172,6 +172,8 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
&AssureMetaTransformer{},
// validate cd & cv's existence and availability
&ValidateAndLoadRefResourcesTransformer{},
+ // normalize the cluster and component API
+ &ClusterAPINormalizationTransformer{},
// handle cluster services
&ClusterServiceTransformer{},
// TODO(component): create default cluster connection credential secret object
diff --git a/controllers/apps/cluster_plan_builder.go b/controllers/apps/cluster_plan_builder.go
index 8b44061b126..5d5e2a5df43 100644
--- a/controllers/apps/cluster_plan_builder.go
+++ b/controllers/apps/cluster_plan_builder.go
@@ -64,11 +64,12 @@ type clusterTransformContext struct {
Client roclient.ReadonlyClient
record.EventRecorder
logr.Logger
- Cluster *appsv1alpha1.Cluster
- OrigCluster *appsv1alpha1.Cluster
- ClusterDef *appsv1alpha1.ClusterDefinition
- ClusterVer *appsv1alpha1.ClusterVersion
- ComponentDefs map[string]*appsv1alpha1.ComponentDefinition // TODO(component)
+ Cluster *appsv1alpha1.Cluster
+ OrigCluster *appsv1alpha1.Cluster
+ ClusterDef *appsv1alpha1.ClusterDefinition
+ ClusterVer *appsv1alpha1.ClusterVersion
+ ComponentSpecs []*appsv1alpha1.ClusterComponentSpec
+ ComponentDefs map[string]*appsv1alpha1.ComponentDefinition
}
// clusterPlanBuilder a graph.PlanBuilder implementation for Cluster reconciliation
diff --git a/controllers/apps/transformer_cluster_api_normalization.go b/controllers/apps/transformer_cluster_api_normalization.go
new file mode 100644
index 00000000000..512648ca7b0
--- /dev/null
+++ b/controllers/apps/transformer_cluster_api_normalization.go
@@ -0,0 +1,88 @@
+/*
+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 (
+ "fmt"
+
+ appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
+ "github.com/apecloud/kubeblocks/pkg/controller/apiconversion"
+ "github.com/apecloud/kubeblocks/pkg/controller/component"
+ "github.com/apecloud/kubeblocks/pkg/controller/graph"
+ "github.com/apecloud/kubeblocks/pkg/controller/model"
+)
+
+// ClusterAPINormalizationTransformer handles cluster and component API conversion.
+type ClusterAPINormalizationTransformer struct{}
+
+var _ graph.Transformer = &ClusterAPINormalizationTransformer{}
+
+func (t *ClusterAPINormalizationTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error {
+ transCtx, _ := ctx.(*clusterTransformContext)
+ if model.IsObjectDeleting(transCtx.OrigCluster) {
+ return nil
+ }
+
+ // build all component specs
+ transCtx.ComponentSpecs = make([]*appsv1alpha1.ClusterComponentSpec, 0)
+ cluster := transCtx.Cluster
+ for i := range cluster.Spec.ComponentSpecs {
+ transCtx.ComponentSpecs = append(transCtx.ComponentSpecs, &cluster.Spec.ComponentSpecs[i])
+ }
+ if compSpec := apiconversion.HandleSimplifiedClusterAPI(cluster, transCtx.ClusterDef); compSpec != nil {
+ transCtx.ComponentSpecs = append(transCtx.ComponentSpecs, compSpec)
+ }
+
+ // build all component definitions referenced
+ if transCtx.ComponentDefs == nil {
+ transCtx.ComponentDefs = make(map[string]*appsv1alpha1.ComponentDefinition)
+ }
+ for i, compSpec := range transCtx.ComponentSpecs {
+ if len(compSpec.ComponentDef) == 0 {
+ compDef, err := t.buildComponentDefinition(transCtx, compSpec)
+ if err != nil {
+ return err
+ }
+ transCtx.ComponentDefs[compDef.Name] = compDef
+ transCtx.ComponentSpecs[i].ComponentDef = compDef.Name
+ } else {
+ if _, ok := transCtx.ComponentDefs[compSpec.ComponentDef]; !ok {
+ panic(fmt.Sprintf("runtime error - expected component definition object not found: %s", compSpec.ComponentDef))
+ }
+ }
+ }
+ return nil
+}
+
+func (t *ClusterAPINormalizationTransformer) buildComponentDefinition(transCtx *clusterTransformContext,
+ clusterCompSpec *appsv1alpha1.ClusterComponentSpec) (*appsv1alpha1.ComponentDefinition, error) {
+ if clusterCompSpec.ComponentDefRef == "" {
+ return nil, fmt.Errorf("expected cluster component def ref is empty: %s-%s", transCtx.Cluster.Name, clusterCompSpec.Name)
+ }
+ clusterCompDef := transCtx.ClusterDef.GetComponentDefByName(clusterCompSpec.ComponentDefRef)
+ if clusterCompDef == nil {
+ return nil, fmt.Errorf("referenced cluster component def is not defined: %s-%s", transCtx.Cluster.Name, clusterCompSpec.Name)
+ }
+ var clusterCompVer *appsv1alpha1.ClusterComponentVersion
+ if transCtx.ClusterVer != nil {
+ clusterCompVer = transCtx.ClusterVer.Spec.GetDefNameMappingComponents()[clusterCompSpec.ComponentDefRef]
+ }
+ return component.BuildComponentDefinitionFrom(clusterCompDef, clusterCompVer, transCtx.Cluster.Name)
+}
diff --git a/controllers/apps/transformer_cluster_component.go b/controllers/apps/transformer_cluster_component.go
index e4382d67f7e..8577b0c634d 100644
--- a/controllers/apps/transformer_cluster_component.go
+++ b/controllers/apps/transformer_cluster_component.go
@@ -55,12 +55,14 @@ func (c *ClusterComponentTransformer) Transform(ctx graph.TransformContext, dag
return nil
}
- if cluster.Spec.ComponentSpecs == nil {
+ // has no components defined
+ if len(transCtx.ComponentSpecs) == 0 {
return nil
}
+
protoCompSpecMap := make(map[string]*appsv1alpha1.ClusterComponentSpec)
- for _, spec := range cluster.Spec.ComponentSpecs {
- protoCompSpecMap[spec.Name] = &spec
+ for _, spec := range transCtx.ComponentSpecs {
+ protoCompSpecMap[spec.Name] = spec
}
protoCompSet := sets.KeySet(protoCompSpecMap)
@@ -73,35 +75,31 @@ func (c *ClusterComponentTransformer) Transform(ctx graph.TransformContext, dag
createCompObjects := func() error {
for compName := range createCompSet {
- protoComp, err := component.BuildProtoComponent(reqCtx, c.Client, cluster, protoCompSpecMap[compName])
+ comp, err := component.BuildProtoComponent2(cluster, protoCompSpecMap[compName])
if err != nil {
return err
}
- graphCli.Create(dag, protoComp)
+ graphCli.Create(dag, comp)
}
return nil
}
updateCompObjects := func() error {
for compName := range updateCompSet {
- runningComp, err := getCacheSnapshotComp(reqCtx, c.Client, compName, cluster.Namespace)
- if err != nil && apierrors.IsNotFound(err) {
- // to be backwards compatible with old API versions, for components that are already running but don't have a component CR, component CR needs to be generated.
- protoComp, err := component.BuildProtoComponent(reqCtx, c.Client, cluster, protoCompSpecMap[compName])
- if err != nil {
- return err
- }
- graphCli.Create(dag, protoComp)
- continue
- } else if err != nil {
- return err
+ runningComp, err1 := getCacheSnapshotComp(reqCtx, c.Client, compName, cluster.Namespace)
+ if err1 != nil && !apierrors.IsNotFound(err1) {
+ return err1
}
- protoComp, err := component.BuildProtoComponent(reqCtx, c.Client, cluster, protoCompSpecMap[compName])
- if err != nil {
- return err
+ comp, err2 := component.BuildProtoComponent2(cluster, protoCompSpecMap[compName])
+ if err2 != nil {
+ return err2
+ }
+ if err1 != nil { // non-exist
+ // to be backwards compatible with old API versions, for components that are already running but don't have a component CR, component CR needs to be generated.
+ graphCli.Create(dag, comp)
+ } else {
+ graphCli.Update(dag, runningComp, copyAndMergeComponent(runningComp, comp, cluster))
}
- newObj := copyAndMergeComponent(runningComp, protoComp, cluster)
- graphCli.Update(dag, runningComp, newObj)
}
return nil
}
@@ -167,9 +165,9 @@ func copyAndMergeComponent(oldCompObj, newCompObj *appsv1alpha1.Component, clust
// getCacheSnapshotComp gets the component object from cache snapshot
func getCacheSnapshotComp(reqCtx ictrlutil.RequestCtx, cli client.Client, compName, namespace string) (*appsv1alpha1.Component, error) {
- runningComp := &appsv1alpha1.Component{}
- if err := ictrlutil.ValidateExistence(reqCtx.Ctx, cli, types.NamespacedName{Name: compName, Namespace: namespace}, runningComp, false); err != nil {
+ comp := &appsv1alpha1.Component{}
+ if err := ictrlutil.ValidateExistence(reqCtx.Ctx, cli, types.NamespacedName{Name: compName, Namespace: namespace}, comp, false); err != nil {
return nil, err
}
- return runningComp, nil
+ return comp, nil
}
diff --git a/controllers/apps/transformer_validate_and_load_ref_resources.go b/controllers/apps/transformer_validate_and_load_ref_resources.go
index 692d91155cc..612d12312cc 100644
--- a/controllers/apps/transformer_validate_and_load_ref_resources.go
+++ b/controllers/apps/transformer_validate_and_load_ref_resources.go
@@ -33,6 +33,8 @@ import (
// ValidateAndLoadRefResourcesTransformer handles referenced resources'(cd & cv) validation and load them into context
type ValidateAndLoadRefResourcesTransformer struct{}
+var _ graph.Transformer = &ValidateAndLoadRefResourcesTransformer{}
+
func (t *ValidateAndLoadRefResourcesTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error {
transCtx, _ := ctx.(*clusterTransformContext)
cluster := transCtx.Cluster
@@ -82,7 +84,29 @@ func (t *ValidateAndLoadRefResourcesTransformer) Transform(ctx graph.TransformCo
transCtx.ClusterVer = &appsv1alpha1.ClusterVersion{}
}
+ if err = t.checkComponentDefinitions(transCtx, cluster); err != nil {
+ return newRequeueError(requeueDuration, err.Error())
+ }
+
return nil
}
-var _ graph.Transformer = &ValidateAndLoadRefResourcesTransformer{}
+func (t *ValidateAndLoadRefResourcesTransformer) checkComponentDefinitions(ctx *clusterTransformContext, cluster *appsv1alpha1.Cluster) error {
+ for _, comp := range cluster.Spec.ComponentSpecs {
+ if len(comp.ComponentDef) == 0 {
+ continue
+ }
+ compDef := &appsv1alpha1.ComponentDefinition{}
+ if err := ctx.Client.Get(ctx.Context, types.NamespacedName{Name: comp.ComponentDef}, compDef); err != nil {
+ return err
+ }
+ if compDef.Status.Phase != appsv1alpha1.AvailablePhase {
+ return fmt.Errorf("the componetn definition referenced is unavailable: %s", comp.ComponentDef)
+ }
+ if ctx.ComponentDefs == nil {
+ ctx.ComponentDefs = make(map[string]*appsv1alpha1.ComponentDefinition)
+ }
+ ctx.ComponentDefs[compDef.Name] = compDef
+ }
+ return nil
+}
diff --git a/pkg/controller/apiconversion/simplified_cluster_api.go b/pkg/controller/apiconversion/simplified_cluster_api.go
new file mode 100644
index 00000000000..16d3083825e
--- /dev/null
+++ b/pkg/controller/apiconversion/simplified_cluster_api.go
@@ -0,0 +1,180 @@
+/*
+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 apiconversion
+
+import (
+ "strings"
+
+ "github.com/spf13/viper"
+ corev1 "k8s.io/api/core/v1"
+
+ appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
+ "github.com/apecloud/kubeblocks/pkg/constant"
+)
+
+// TODO(xingran): HandleSimplifiedClusterAPI should also support the new component definition API.
+
+// HandleSimplifiedClusterAPI handles simplified api for cluster.
+func HandleSimplifiedClusterAPI(cluster *appsv1alpha1.Cluster, clusterDef *appsv1alpha1.ClusterDefinition) *appsv1alpha1.ClusterComponentSpec {
+ if hasClusterCompDefined(cluster) {
+ return nil
+ }
+ if !hasSimplifiedClusterAPI(cluster) {
+ return nil
+ }
+ if len(clusterDef.Spec.ComponentDefs) == 0 {
+ return nil
+ }
+ // fill simplified api only to first defined component
+ return fillSimplifiedClusterAPI(cluster, &clusterDef.Spec.ComponentDefs[0])
+}
+
+func hasClusterCompDefined(cluster *appsv1alpha1.Cluster) bool {
+ return cluster.Spec.ComponentSpecs != nil && len(cluster.Spec.ComponentSpecs) > 0
+}
+
+func hasSimplifiedClusterAPI(cluster *appsv1alpha1.Cluster) bool {
+ return cluster.Spec.Replicas != nil ||
+ !cluster.Spec.Resources.CPU.IsZero() ||
+ !cluster.Spec.Resources.Memory.IsZero() ||
+ !cluster.Spec.Storage.Size.IsZero() ||
+ cluster.Spec.Monitor.MonitoringInterval != nil ||
+ cluster.Spec.Network != nil ||
+ len(cluster.Spec.Tenancy) > 0 ||
+ len(cluster.Spec.AvailabilityPolicy) > 0
+}
+
+func fillSimplifiedClusterAPI(cluster *appsv1alpha1.Cluster, clusterCompDef *appsv1alpha1.ClusterComponentDefinition) *appsv1alpha1.ClusterComponentSpec {
+ clusterCompSpec := &appsv1alpha1.ClusterComponentSpec{
+ Name: clusterCompDef.Name,
+ }
+ if cluster.Spec.Replicas != nil {
+ clusterCompSpec.Replicas = *cluster.Spec.Replicas
+ }
+ dataVolumeName := "data"
+ for _, v := range clusterCompDef.VolumeTypes {
+ if v.Type == appsv1alpha1.VolumeTypeData {
+ dataVolumeName = v.Name
+ }
+ }
+ if !cluster.Spec.Resources.CPU.IsZero() || !cluster.Spec.Resources.Memory.IsZero() {
+ clusterCompSpec.Resources.Limits = corev1.ResourceList{}
+ }
+ if !cluster.Spec.Resources.CPU.IsZero() {
+ clusterCompSpec.Resources.Limits["cpu"] = cluster.Spec.Resources.CPU
+ }
+ if !cluster.Spec.Resources.Memory.IsZero() {
+ clusterCompSpec.Resources.Limits["memory"] = cluster.Spec.Resources.Memory
+ }
+ if !cluster.Spec.Storage.Size.IsZero() {
+ clusterCompSpec.VolumeClaimTemplates = []appsv1alpha1.ClusterComponentVolumeClaimTemplate{
+ {
+ Name: dataVolumeName,
+ Spec: appsv1alpha1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{
+ corev1.ReadWriteOnce,
+ },
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ "storage": cluster.Spec.Storage.Size,
+ },
+ },
+ },
+ },
+ }
+ }
+ if cluster.Spec.Monitor.MonitoringInterval != nil {
+ if len(cluster.Spec.Monitor.MonitoringInterval.StrVal) == 0 && cluster.Spec.Monitor.MonitoringInterval.IntVal == 0 {
+ clusterCompSpec.Monitor = false
+ } else {
+ clusterCompSpec.Monitor = true
+ // TODO: should also set interval
+ }
+ }
+ if cluster.Spec.Network != nil {
+ clusterCompSpec.Services = []appsv1alpha1.ClusterComponentService{}
+ if cluster.Spec.Network.HostNetworkAccessible {
+ svc := appsv1alpha1.ClusterComponentService{
+ Name: "vpc",
+ ServiceType: "LoadBalancer",
+ }
+ switch getCloudProvider() {
+ case cloudProviderAWS:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/aws-load-balancer-type": "nlb",
+ "service.beta.kubernetes.io/aws-load-balancer-internal": "true",
+ }
+ case cloudProviderGCP:
+ svc.Annotations = map[string]string{
+ "networking.gke.io/load-balancer-type": "Internal",
+ }
+ case cloudProviderAliyun:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type": "intranet",
+ }
+ case cloudProviderAzure:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/azure-load-balancer-internal": "true",
+ }
+ }
+ clusterCompSpec.Services = append(clusterCompSpec.Services, svc)
+ }
+ if cluster.Spec.Network.PubliclyAccessible {
+ svc := appsv1alpha1.ClusterComponentService{
+ Name: "public",
+ ServiceType: "LoadBalancer",
+ }
+ switch getCloudProvider() {
+ case cloudProviderAWS:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/aws-load-balancer-type": "nlb",
+ "service.beta.kubernetes.io/aws-load-balancer-internal": "false",
+ }
+ case cloudProviderAliyun:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type": "internet",
+ }
+ case cloudProviderAzure:
+ svc.Annotations = map[string]string{
+ "service.beta.kubernetes.io/azure-load-balancer-internal": "false",
+ }
+ }
+ clusterCompSpec.Services = append(clusterCompSpec.Services, svc)
+ }
+ }
+ return clusterCompSpec
+}
+
+func getCloudProvider() cloudProvider {
+ k8sVersion := viper.GetString(constant.CfgKeyServerInfo)
+ if strings.Contains(k8sVersion, "eks") {
+ return cloudProviderAWS
+ }
+ if strings.Contains(k8sVersion, "gke") {
+ return cloudProviderGCP
+ }
+ if strings.Contains(k8sVersion, "aliyun") {
+ return cloudProviderAliyun
+ }
+ if strings.Contains(k8sVersion, "tke") {
+ return cloudProviderTencent
+ }
+ return cloudProviderUnknown
+}
diff --git a/pkg/controller/apiconversion/type.go b/pkg/controller/apiconversion/type.go
new file mode 100644
index 00000000000..7a91e7b66d8
--- /dev/null
+++ b/pkg/controller/apiconversion/type.go
@@ -0,0 +1,31 @@
+/*
+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 apiconversion
+
+type cloudProvider string
+
+const (
+ cloudProviderAWS cloudProvider = "aws"
+ cloudProviderGCP cloudProvider = "gcp"
+ cloudProviderAliyun cloudProvider = "aliyun"
+ cloudProviderAzure cloudProvider = "azure"
+ cloudProviderTencent cloudProvider = "tencent"
+ cloudProviderUnknown cloudProvider = "unknown"
+)
diff --git a/pkg/controller/component/component.go b/pkg/controller/component/component.go
index a9c676606dc..555b437a96c 100644
--- a/pkg/controller/component/component.go
+++ b/pkg/controller/component/component.go
@@ -50,6 +50,25 @@ func BuildProtoComponent(reqCtx ictrlutil.RequestCtx,
return buildProtoCompFromConvertor(reqCtx, cli, cluster, clusterCompSpec)
}
+// BuildProtoComponent2 builds a new Component object from cluster component spec and definition.
+func BuildProtoComponent2(cluster *appsv1alpha1.Cluster,
+ clusterCompSpec *appsv1alpha1.ClusterComponentSpec) (*appsv1alpha1.Component, error) {
+ builder := builder.NewComponentBuilder(cluster.Namespace, clusterCompSpec.Name, cluster.Name, clusterCompSpec.ComponentDef).
+ SetAffinity(clusterCompSpec.Affinity).
+ SetTolerations(clusterCompSpec.Tolerations).
+ SetReplicas(clusterCompSpec.Replicas).
+ SetResources(clusterCompSpec.Resources).
+ SetMonitor(clusterCompSpec.Monitor).
+ SetServiceAccountName(clusterCompSpec.ServiceAccountName).
+ SetVolumeClaimTemplates(clusterCompSpec.VolumeClaimTemplates).
+ SetUpdateStrategy(clusterCompSpec.UpdateStrategy).
+ SetEnabledLogs(clusterCompSpec.EnabledLogs).
+ SetServiceRefs(clusterCompSpec.ServiceRefs).
+ SetClassRef(clusterCompSpec.ClassDefRef).
+ SetTLSConfig(clusterCompSpec.TLS, clusterCompSpec.Issuer)
+ return builder.GetObject(), nil
+}
+
// BuildComponentDefinition constructs a ComponentDefinition object based on the following rules:
// 1. If the clusterCompSpec.EnableComponentDefinition feature gate is enabled, return the ComponentDefinition object corresponding to clusterCompSpec.ComponentDef directly.
// 2. Otherwise, generate the corresponding ComponentDefinition object from converting clusterComponentDefinition.
diff --git a/pkg/controller/component/component_definition_convertor_test.go b/pkg/controller/component/component_definition_convertor_test.go
index fb73db45dd7..de208a556ad 100644
--- a/pkg/controller/component/component_definition_convertor_test.go
+++ b/pkg/controller/component/component_definition_convertor_test.go
@@ -56,7 +56,7 @@ var _ = Describe("Component Definition Convertor", func() {
WorkloadType: appsv1alpha1.Consensus,
CharacterType: "mysql",
ConfigSpecs: []appsv1alpha1.ComponentConfigSpec{
- appsv1alpha1.ComponentConfigSpec{
+ {
ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{
Name: "mysql-config",
TemplateRef: "mysql-config-template",
@@ -67,7 +67,7 @@ var _ = Describe("Component Definition Convertor", func() {
},
},
ScriptSpecs: []appsv1alpha1.ComponentTemplateSpec{
- appsv1alpha1.ComponentTemplateSpec{
+ {
Name: "mysql-scripts",
TemplateRef: "mysql-scripts",
VolumeName: "scripts",
@@ -92,15 +92,15 @@ var _ = Describe("Component Definition Convertor", func() {
},
},
LogConfigs: []appsv1alpha1.LogConfig{
- appsv1alpha1.LogConfig{
+ {
Name: "error",
FilePathPattern: "/data/mysql/log/mysqld-error.log",
},
- appsv1alpha1.LogConfig{
+ {
Name: "slow",
FilePathPattern: "/data/mysql/log/mysqld-slowquery.log",
},
- appsv1alpha1.LogConfig{
+ {
Name: "general",
FilePathPattern: "/data/mysql/log/mysqld.log",
},
@@ -108,31 +108,31 @@ var _ = Describe("Component Definition Convertor", func() {
PodSpec: &corev1.PodSpec{
Volumes: []corev1.Volume{},
Containers: []corev1.Container{
- corev1.Container{
+ {
Name: "mysql",
Command: []string{"/entrypoint.sh"},
Env: []corev1.EnvVar{
- corev1.EnvVar{
+ {
Name: "port",
Value: "3306",
},
},
VolumeMounts: []corev1.VolumeMount{
- corev1.VolumeMount{
+ {
Name: dataVolumeName,
MountPath: "/data/mysql",
},
- corev1.VolumeMount{
+ {
Name: logVolumeName,
MountPath: "/data/log",
},
},
Ports: []corev1.ContainerPort{
- corev1.ContainerPort{
+ {
Name: "mysql",
ContainerPort: 3306,
},
- corev1.ContainerPort{
+ {
Name: "paxos",
ContainerPort: 13306,
},
@@ -153,7 +153,7 @@ var _ = Describe("Component Definition Convertor", func() {
},
Service: &appsv1alpha1.ServiceSpec{
Ports: []appsv1alpha1.ServicePort{
- appsv1alpha1.ServicePort{
+ {
Name: "data",
Port: 3306,
TargetPort: intstr.IntOrString{
@@ -161,7 +161,7 @@ var _ = Describe("Component Definition Convertor", func() {
StrVal: "mysql",
},
},
- appsv1alpha1.ServicePort{
+ {
Name: "paxos",
Port: 13306,
TargetPort: intstr.IntOrString{
@@ -179,7 +179,7 @@ var _ = Describe("Component Definition Convertor", func() {
AccessMode: appsv1alpha1.ReadWrite,
},
Followers: []appsv1alpha1.ConsensusMember{
- appsv1alpha1.ConsensusMember{
+ {
Name: "follower",
AccessMode: appsv1alpha1.Readonly,
},
@@ -197,11 +197,11 @@ var _ = Describe("Component Definition Convertor", func() {
CommandExecutorEnvItem: appsv1alpha1.CommandExecutorEnvItem{
Image: "image",
Env: []corev1.EnvVar{
- corev1.EnvVar{
+ {
Name: "user",
Value: "user",
},
- corev1.EnvVar{
+ {
Name: "password",
Value: "password",
},
@@ -219,7 +219,7 @@ var _ = Describe("Component Definition Convertor", func() {
LetterCase: appsv1alpha1.MixedCases,
},
Accounts: []appsv1alpha1.SystemAccountConfig{
- appsv1alpha1.SystemAccountConfig{
+ {
Name: appsv1alpha1.AdminAccount,
ProvisionPolicy: appsv1alpha1.ProvisionPolicy{
Type: appsv1alpha1.CreateByStmt,
@@ -229,7 +229,7 @@ var _ = Describe("Component Definition Convertor", func() {
},
},
},
- appsv1alpha1.SystemAccountConfig{
+ {
Name: appsv1alpha1.ReplicatorAccount,
ProvisionPolicy: appsv1alpha1.ProvisionPolicy{
Type: appsv1alpha1.ReferToExisting,
@@ -242,21 +242,21 @@ var _ = Describe("Component Definition Convertor", func() {
},
},
VolumeTypes: []appsv1alpha1.VolumeTypeSpec{
- appsv1alpha1.VolumeTypeSpec{
+ {
Name: dataVolumeName,
Type: appsv1alpha1.VolumeTypeData,
},
- appsv1alpha1.VolumeTypeSpec{
+ {
Name: logVolumeName,
Type: appsv1alpha1.VolumeTypeLog,
},
},
CustomLabelSpecs: []appsv1alpha1.CustomLabelSpec{
- appsv1alpha1.CustomLabelSpec{
+ {
Key: "scope",
Value: "scope",
Resources: []appsv1alpha1.GVKResource{
- appsv1alpha1.GVKResource{
+ {
GVK: "v1/pod",
Selector: map[string]string{
"managed-by": "kubeblocks",
@@ -269,7 +269,7 @@ var _ = Describe("Component Definition Convertor", func() {
VolumeProtectionSpec: &appsv1alpha1.VolumeProtectionSpec{
HighWatermark: defaultHighWatermark,
Volumes: []appsv1alpha1.ProtectedVolume{
- appsv1alpha1.ProtectedVolume{
+ {
Name: logVolumeName,
HighWatermark: &lowerHighWatermark,
},
@@ -330,13 +330,13 @@ var _ = Describe("Component Definition Convertor", func() {
clusterCompVer := &appsv1alpha1.ClusterComponentVersion{
VersionsCtx: appsv1alpha1.VersionsContext{
InitContainers: []corev1.Container{
- corev1.Container{
+ {
Name: "init",
Image: "init",
},
},
Containers: []corev1.Container{
- corev1.Container{
+ {
Name: "mysql",
Image: "image",
},
@@ -462,7 +462,7 @@ var _ = Describe("Component Definition Convertor", func() {
It("w/ comp version", func() {
clusterCompVer := &appsv1alpha1.ClusterComponentVersion{
ConfigSpecs: []appsv1alpha1.ComponentConfigSpec{
- appsv1alpha1.ComponentConfigSpec{
+ {
ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{
Name: "agamotto-config",
TemplateRef: "agamotto-config-template",
@@ -545,12 +545,12 @@ var _ = Describe("Component Definition Convertor", func() {
Expect(err).Should(Succeed())
expectedAccounts := []appsv1alpha1.ComponentSystemAccount{
- appsv1alpha1.ComponentSystemAccount{
+ {
Name: string(clusterCompDef.SystemAccounts.Accounts[0].Name),
PasswordGenerationPolicy: clusterCompDef.SystemAccounts.PasswordConfig,
Statement: clusterCompDef.SystemAccounts.Accounts[0].ProvisionPolicy.Statements.CreationStatement,
},
- appsv1alpha1.ComponentSystemAccount{
+ {
Name: string(clusterCompDef.SystemAccounts.Accounts[1].Name),
PasswordGenerationPolicy: clusterCompDef.SystemAccounts.PasswordConfig,
SecretRef: clusterCompDef.SystemAccounts.Accounts[1].ProvisionPolicy.SecretRef,
@@ -612,17 +612,17 @@ var _ = Describe("Component Definition Convertor", func() {
Expect(err).Should(Succeed())
expectedRoles := []appsv1alpha1.ComponentReplicaRole{
- appsv1alpha1.ComponentReplicaRole{
+ {
Name: "leader",
Serviceable: true,
Writable: true,
},
- appsv1alpha1.ComponentReplicaRole{
+ {
Name: "follower",
Serviceable: true,
Writable: false,
},
- appsv1alpha1.ComponentReplicaRole{
+ {
Name: "learner",
Serviceable: true,
Writable: false,
diff --git a/pkg/controller/component/rsm_convertor.go b/pkg/controller/component/rsm_convertor.go
index a2071bc3293..2cc42abe626 100644
--- a/pkg/controller/component/rsm_convertor.go
+++ b/pkg/controller/component/rsm_convertor.go
@@ -22,11 +22,11 @@ package component
import (
"errors"
- "github.com/apecloud/kubeblocks/pkg/constant"
corev1 "k8s.io/api/core/v1"
appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1alpha1"
+ "github.com/apecloud/kubeblocks/pkg/constant"
)
// BuildRSMFrom builds a new Component object based on Cluster, SynthesizedComponent.