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.