From 4e66a362503c71d07993c58c3eaecfb15c2cecb6 Mon Sep 17 00:00:00 2001 From: xuriwuyun Date: Thu, 28 Sep 2023 13:43:47 +0800 Subject: [PATCH 1/5] fix: lorry leave member (#5246) --- lorry/binding/base.go | 14 ++++++++------ lorry/client/client.go | 4 ++-- lorry/component/dbmanager.go | 12 ++++++++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lorry/binding/base.go b/lorry/binding/base.go index c1d71efa3c7..672f8f36c36 100644 --- a/lorry/binding/base.go +++ b/lorry/binding/base.go @@ -429,10 +429,11 @@ func (ops *BaseOperations) SwitchoverOps(ctx context.Context, req *ProbeRequest, func (ops *BaseOperations) JoinMemberOps(ctx context.Context, req *ProbeRequest, resp *ProbeResponse) (OpsResult, error) { opsRes := OpsResult{} manager, err := component.GetDefaultManager() - if err != nil { - opsRes["event"] = OperationFailed + if manager == nil { + // manager for the DB is not supported, just return + opsRes["event"] = OperationSuccess opsRes["message"] = err.Error() - return opsRes, err + return opsRes, nil } dcsStore := dcs.GetStore() @@ -468,10 +469,11 @@ func (ops *BaseOperations) JoinMemberOps(ctx context.Context, req *ProbeRequest, func (ops *BaseOperations) LeaveMemberOps(ctx context.Context, req *ProbeRequest, resp *ProbeResponse) (OpsResult, error) { opsRes := OpsResult{} manager, err := component.GetDefaultManager() - if err != nil { - opsRes["event"] = OperationFailed + if manager == nil { + // manager for the DB is not supported, just return + opsRes["event"] = OperationSuccess opsRes["message"] = err.Error() - return opsRes, err + return opsRes, nil } dcsStore := dcs.GetStore() diff --git a/lorry/client/client.go b/lorry/client/client.go index a4b22558c74..ac4867398a1 100644 --- a/lorry/client/client.go +++ b/lorry/client/client.go @@ -39,7 +39,7 @@ import ( ) const ( - urlTemplate = "http://localhost:%d/v1.0/bindings/%s" + urlTemplate = "http://%s:%d/v1.0/bindings/%s" ) type Client interface { @@ -123,7 +123,7 @@ func NewClientWithPod(pod *corev1.Pod, characterType string) (*OperationClient, Client: client, Port: port, CharacterType: characterType, - URL: fmt.Sprintf(urlTemplate, port, characterType), + URL: fmt.Sprintf(urlTemplate, ip, port, characterType), CacheTTL: 60 * time.Second, RequestTimeout: 30 * time.Second, ReconcileTimeout: 500 * time.Millisecond, diff --git a/lorry/component/dbmanager.go b/lorry/component/dbmanager.go index 2ed4db855b9..9406e351388 100644 --- a/lorry/component/dbmanager.go +++ b/lorry/component/dbmanager.go @@ -222,6 +222,14 @@ func (mgr *DBManagerBase) ShutDownWithWait() { mgr.Logger.Info("Override me if need") } +func (*DBManagerBase) JoinCurrentMemberToCluster(context.Context, *dcs.Cluster) error { + return nil +} + +func (*DBManagerBase) LeaveMemberFromCluster(context.Context, *dcs.Cluster, string) error { + return nil +} + func RegisterManager(characterType, workloadType string, manager DBManager) { key := strings.ToLower(characterType + "_" + workloadType) managers[key] = manager @@ -306,11 +314,11 @@ func (*FakeManager) IsFirstMember() bool { } func (*FakeManager) JoinCurrentMemberToCluster(context.Context, *dcs.Cluster) error { - return fmt.Errorf("NotSupported") + return nil } func (*FakeManager) LeaveMemberFromCluster(context.Context, *dcs.Cluster, string) error { - return fmt.Errorf("NotSuppported") + return nil } func (*FakeManager) Promote(context.Context, *dcs.Cluster) error { From beca3452bc9a17179938cba6cd00ec6bf0662501 Mon Sep 17 00:00:00 2001 From: huangzhangshu <109708205+JashBook@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:05:16 +0800 Subject: [PATCH 2/5] chore: COPY go. mod instead of bind (#5309) --- .github/workflows/cicd-pull-request.yml | 2 +- .github/workflows/cicd-push.yml | 2 +- .github/workflows/release-image.yml | 2 +- docker/Dockerfile | 7 +++---- docker/Dockerfile-dataprotection | 7 +++---- docker/Dockerfile-tools | 7 +++---- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/cicd-pull-request.yml b/.github/workflows/cicd-pull-request.yml index 65d981cd6ca..66bd6e4e9c3 100644 --- a/.github/workflows/cicd-pull-request.yml +++ b/.github/workflows/cicd-pull-request.yml @@ -156,7 +156,7 @@ jobs: if: contains(needs.trigger-mode.outputs.trigger-mode, '[docker]') uses: apecloud/apecloud-cd/.github/workflows/release-image-check.yml@v0.1.24 with: - MAKE_OPS_PRE: "generate test-go-generate" + MAKE_OPS_PRE: "module generate test-go-generate" IMG: "apecloud/kubeblocks-tools" GO_VERSION: "1.21" BUILDX_PLATFORMS: "linux/amd64" diff --git a/.github/workflows/cicd-push.yml b/.github/workflows/cicd-push.yml index 86136657854..d682d5beb6d 100644 --- a/.github/workflows/cicd-push.yml +++ b/.github/workflows/cicd-push.yml @@ -205,7 +205,7 @@ jobs: if: ${{ contains(needs.trigger-mode.outputs.trigger-mode, '[docker]') }} uses: apecloud/apecloud-cd/.github/workflows/release-image-check.yml@v0.1.24 with: - MAKE_OPS_PRE: "generate test-go-generate" + MAKE_OPS_PRE: "module generate test-go-generate" IMG: "apecloud/kubeblocks-tools" GO_VERSION: "1.21" BUILDX_PLATFORMS: "linux/amd64" diff --git a/.github/workflows/release-image.yml b/.github/workflows/release-image.yml index eab510cd9ff..00f1b4c62b2 100644 --- a/.github/workflows/release-image.yml +++ b/.github/workflows/release-image.yml @@ -54,7 +54,7 @@ jobs: needs: image-tag uses: apecloud/apecloud-cd/.github/workflows/release-image-cache.yml@v0.1.24 with: - MAKE_OPS_PRE: "generate test-go-generate" + MAKE_OPS_PRE: "module generate test-go-generate" IMG: "apecloud/kubeblocks-tools" VERSION: "${{ needs.image-tag.outputs.tag-name }}" GO_VERSION: "1.21" diff --git a/docker/Dockerfile b/docker/Dockerfile index dc92fe13020..7800c67aa68 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,12 +26,11 @@ ENV GOPROXY=${GOPROXY} WORKDIR /src # Copy the Go Modules manifests -#COPY go.mod go.mod -#COPY go.sum go.sum +COPY go.mod go.mod +COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer -RUN --mount=type=bind,target=. \ - --mount=type=cache,target=/go/pkg/mod \ +RUN --mount=type=cache,target=/go/pkg/mod \ go mod download # Copy the go source diff --git a/docker/Dockerfile-dataprotection b/docker/Dockerfile-dataprotection index d571c22f008..45b6349d545 100644 --- a/docker/Dockerfile-dataprotection +++ b/docker/Dockerfile-dataprotection @@ -26,12 +26,11 @@ ENV GOPROXY=${GOPROXY} WORKDIR /src # Copy the Go Modules manifests -#COPY go.mod go.mod -#COPY go.sum go.sum +COPY go.mod go.mod +COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer -RUN --mount=type=bind,target=. \ - --mount=type=cache,target=/go/pkg/mod \ +RUN --mount=type=cache,target=/go/pkg/mod \ go mod download # Copy the go source diff --git a/docker/Dockerfile-tools b/docker/Dockerfile-tools index 7110809899b..ea7f76feb7b 100644 --- a/docker/Dockerfile-tools +++ b/docker/Dockerfile-tools @@ -28,8 +28,8 @@ ENV GOPROXY=${GOPROXY} WORKDIR /src # Copy the Go Modules manifests -#COPY go.mod go.mod -#COPY go.sum go.sum +COPY go.mod go.mod +COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer # RUN go mod download @@ -44,8 +44,7 @@ WORKDIR /src #COPY cmd/cli/ cmd/cli/ #COPY apis/ apis/ #COPY test/testdata/testdata.go test/testdata/testdata.go -RUN --mount=type=bind,target=. \ - --mount=type=cache,target=/go/pkg/mod \ +RUN --mount=type=cache,target=/go/pkg/mod \ go mod download # Build From 2536a1cf0d0e21985b5f8f2e2b2943af7d9dfb61 Mon Sep 17 00:00:00 2001 From: dingben Date: Sat, 30 Sep 2023 17:04:54 +0800 Subject: [PATCH 3/5] feat: cli plugin adapt the change of block index repository (#5305) --- internal/cli/cmd/plugin/types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/cli/cmd/plugin/types.go b/internal/cli/cmd/plugin/types.go index e05767dc8e4..1480511352c 100644 --- a/internal/cli/cmd/plugin/types.go +++ b/internal/cli/cmd/plugin/types.go @@ -67,6 +67,9 @@ func (p *Paths) IndexPluginsPath(name string) []string { if _, err := os.Stat(filepath.Join(p.IndexPath(name), "krew-plugins")); err == nil { result = append(result, filepath.Join(p.IndexPath(name), "krew-plugins")) } + if _, err := os.Stat(filepath.Join(p.IndexPath(name), "cli-plugins")); err == nil { + result = append(result, filepath.Join(p.IndexPath(name), "cli-plugins")) + } return result } From bc7b19311318d8a5cf0b849b20e53b4812f73f0a Mon Sep 17 00:00:00 2001 From: a le <101848970+1aal@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:19:50 +0800 Subject: [PATCH 4/5] fix: supply the docker error info when playground init locally failed (#5315) --- internal/cli/util/version.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/cli/util/version.go b/internal/cli/util/version.go index 9f2cd2ed4d8..ae24154ae4a 100644 --- a/internal/cli/util/version.go +++ b/internal/cli/util/version.go @@ -20,6 +20,7 @@ along with this program. If not, see . package util import ( + "bytes" "context" "fmt" "os/exec" @@ -128,9 +129,15 @@ func GetKubeBlocksDeploy(client kubernetes.Interface) (*appsv1.Deployment, error func GetDockerVersion() (*gv.Version, error) { // exec cmd to get output from docker info --format '{{.ServerVersion}}' cmd := exec.Command("docker", "info", "--format", "{{.ServerVersion}}") + var stderr bytes.Buffer + cmd.Stderr = &stderr out, err := cmd.Output() - if err != nil { - return nil, err + if err != nil || stderr.String() != "" { + errMsg := stderr.String() + if errMsg == "" { + errMsg = err.Error() + } + return nil, fmt.Errorf("failed to get the docker version by executing \"docker info --format {{.ServerVersion}}\": %s", errMsg) } return gv.NewVersion(strings.TrimSpace(string(out))) } From 1f87a871a8fefc06891fd22b68d029b85a443dd6 Mon Sep 17 00:00:00 2001 From: zhangtao <111836083+sophon-zt@users.noreply.github.com> Date: Fri, 6 Oct 2023 21:47:38 -0500 Subject: [PATCH 5/5] chore: refine configuration reconcile and phase (#5311) --- apis/apps/v1alpha1/config.go | 3 +- .../apps.kubeblocks.io_configurations.yaml | 1 + .../configuration/configuration_controller.go | 62 ++++----- .../apps/configuration/reconcile_task.go | 77 ++++++---- controllers/apps/operations/reconfigure.go | 9 +- .../apps.kubeblocks.io_configurations.yaml | 1 + internal/controller/configuration/pipeline.go | 38 +---- internal/controllerutil/config_util.go | 50 +++++++ internal/controllerutil/config_util_test.go | 131 ++++++++++++++++++ 9 files changed, 271 insertions(+), 101 deletions(-) diff --git a/apis/apps/v1alpha1/config.go b/apis/apps/v1alpha1/config.go index bc91687dd17..c0cf6afbe1c 100644 --- a/apis/apps/v1alpha1/config.go +++ b/apis/apps/v1alpha1/config.go @@ -72,10 +72,11 @@ package v1alpha1 // ConfigurationPhase defines the Configuration FSM phase // +enum -// +kubebuilder:validation:Enum={Init,Running,Pending,Merged,MergeFailed,FailedAndPause,Upgrading,Deleting,FailedAndRetry,Finished} +// +kubebuilder:validation:Enum={Creating,Init,Running,Pending,Merged,MergeFailed,FailedAndPause,Upgrading,Deleting,FailedAndRetry,Finished} type ConfigurationPhase string const ( + CCreatingPhase ConfigurationPhase = "Creating" CInitPhase ConfigurationPhase = "Init" CRunningPhase ConfigurationPhase = "Running" CPendingPhase ConfigurationPhase = "Pending" diff --git a/config/crd/bases/apps.kubeblocks.io_configurations.yaml b/config/crd/bases/apps.kubeblocks.io_configurations.yaml index 627422ccfe9..7dbc26db996 100644 --- a/config/crd/bases/apps.kubeblocks.io_configurations.yaml +++ b/config/crd/bases/apps.kubeblocks.io_configurations.yaml @@ -310,6 +310,7 @@ spec: phase: description: phase is status of configurationItem. enum: + - Creating - Init - Running - Pending diff --git a/controllers/apps/configuration/configuration_controller.go b/controllers/apps/configuration/configuration_controller.go index 1d0881d8993..9208d02a498 100644 --- a/controllers/apps/configuration/configuration_controller.go +++ b/controllers/apps/configuration/configuration_controller.go @@ -107,7 +107,7 @@ func (r *ConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Reques return r.failWithInvalidComponent(configuration, reqCtx) } - if err := r.runTasks(reqCtx, configuration, fetcherTask, tasks); err != nil { + if err := r.runTasks(TaskContext{configuration, reqCtx, fetcherTask}, tasks); err != nil { return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "failed to run configuration reconcile task.") } if !isAllReady(configuration) { @@ -130,55 +130,52 @@ func (r *ConfigurationReconciler) failWithInvalidComponent(configuration *appsv1 func isAllReady(configuration *appsv1alpha1.Configuration) bool { for _, item := range configuration.Spec.ConfigItemDetails { itemStatus := configuration.Status.GetItemStatus(item.Name) - if itemStatus == nil || itemStatus.Phase != appsv1alpha1.CFinishedPhase { + if itemStatus != nil && !isFinishStatus(itemStatus.Phase) { return false } } return true } -func (r *ConfigurationReconciler) runTasks( - reqCtx intctrlutil.RequestCtx, - configuration *appsv1alpha1.Configuration, - fetcher *Task, - tasks []Task) (err error) { - var errs []error - var synthesizedComp *component.SynthesizedComponent - - synthesizedComp, err = component.BuildComponent(reqCtx, nil, - fetcher.ClusterObj, - fetcher.ClusterDefObj, - fetcher.ClusterDefComObj, - fetcher.ClusterComObj, +func (r *ConfigurationReconciler) runTasks(taskCtx TaskContext, tasks []Task) (err error) { + var ( + errs []error + synthesizedComp *component.SynthesizedComponent + + ctx = taskCtx.reqCtx.Ctx + configuration = taskCtx.configuration + ) + + synthesizedComp, err = component.BuildComponent(taskCtx.reqCtx, + nil, + taskCtx.fetcher.ClusterObj, + taskCtx.fetcher.ClusterDefObj, + taskCtx.fetcher.ClusterDefComObj, + taskCtx.fetcher.ClusterComObj, nil, - fetcher.ClusterVerComObj) + taskCtx.fetcher.ClusterVerComObj) if err != nil { return err } + // TODO manager multiple version patch := client.MergeFrom(configuration.DeepCopy()) revision := strconv.FormatInt(configuration.GetGeneration(), 10) for _, task := range tasks { - if err := task.Do(fetcher, synthesizedComp, revision); err != nil { + task.Status.UpdateRevision = revision + if err := task.Do(taskCtx.fetcher, synthesizedComp, revision); err != nil { task.Status.Phase = appsv1alpha1.CMergeFailedPhase task.Status.Message = cfgutil.ToPointer(err.Error()) errs = append(errs, err) continue } - task.Status.UpdateRevision = revision - task.Status.Phase = appsv1alpha1.CMergedPhase - if err := task.SyncStatus(fetcher, task.Status); err != nil { - task.Status.Phase = appsv1alpha1.CFailedPhase - task.Status.Message = cfgutil.ToPointer(err.Error()) - errs = append(errs, err) - } } configuration.Status.Message = "" if len(errs) > 0 { configuration.Status.Message = utilerrors.NewAggregate(errs).Error() } - if err := r.Client.Status().Patch(reqCtx.Ctx, configuration, patch); err != nil { + if err := r.Client.Status().Patch(ctx, configuration, patch); err != nil { errs = append(errs, err) } if len(errs) == 0 { @@ -216,12 +213,11 @@ func fromItemStatus(ctx intctrlutil.RequestCtx, status *appsv1alpha1.Configurati } func isReconcileStatus(phase appsv1alpha1.ConfigurationPhase) bool { - return phase == appsv1alpha1.CRunningPhase || - phase == appsv1alpha1.CInitPhase || - phase == appsv1alpha1.CPendingPhase || - phase == appsv1alpha1.CFailedPhase || - phase == appsv1alpha1.CMergedPhase || - phase == appsv1alpha1.CMergeFailedPhase || - phase == appsv1alpha1.CUpgradingPhase || - phase == appsv1alpha1.CFinishedPhase + return phase != "" && + phase != appsv1alpha1.CCreatingPhase && + phase != appsv1alpha1.CDeletingPhase +} + +func isFinishStatus(phase appsv1alpha1.ConfigurationPhase) bool { + return phase == appsv1alpha1.CFinishedPhase || phase == appsv1alpha1.CFailedAndPausePhase } diff --git a/controllers/apps/configuration/reconcile_task.go b/controllers/apps/configuration/reconcile_task.go index 3f4454281b4..03f1510682a 100644 --- a/controllers/apps/configuration/reconcile_task.go +++ b/controllers/apps/configuration/reconcile_task.go @@ -22,6 +22,8 @@ package configuration import ( "strconv" + corev1 "k8s.io/api/core/v1" + appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" "github.com/apecloud/kubeblocks/internal/configuration/core" "github.com/apecloud/kubeblocks/internal/controller/component" @@ -35,46 +37,73 @@ type Task struct { Status *appsv1alpha1.ConfigurationItemDetailStatus Name string - Do func(fetcher *Task, component *component.SynthesizedComponent, revision string) error - SyncStatus func(fetcher *Task, status *appsv1alpha1.ConfigurationItemDetailStatus) error + Do func(fetcher *Task, component *component.SynthesizedComponent, revision string) error +} + +type TaskContext struct { + configuration *appsv1alpha1.Configuration + reqCtx intctrlutil.RequestCtx + fetcher *Task } func NewTask(item appsv1alpha1.ConfigurationItemDetail, status *appsv1alpha1.ConfigurationItemDetailStatus) Task { return Task{ - Name: item.Name, - Status: status, + Name: item.Name, Do: func(fetcher *Task, synComponent *component.SynthesizedComponent, revision string) error { configSpec := item.ConfigSpec if configSpec == nil { return core.MakeError("not found config spec: %s", item.Name) } - reconcileTask := configuration.NewReconcilePipeline(configuration.ReconcileCtx{ - ResourceCtx: fetcher.ResourceCtx, - Cluster: fetcher.ClusterObj, - ClusterVer: fetcher.ClusterVerObj, - Component: synComponent, - PodSpec: synComponent.PodSpec, - }, item, status, configSpec) - return reconcileTask.ConfigMap(item.Name). - ConfigConstraints(configSpec.ConfigConstraintRef). - PrepareForTemplate(). - RerenderTemplate(). - ApplyParameters(). - UpdateConfigVersion(revision). - Sync(). - Complete() + if err := fetcher.ConfigMap(item.Name).Complete(); err != nil { + return err + } + // Do reconcile for config template + configMap := fetcher.ConfigMapObj + switch intctrlutil.GetConfigSpecReconcilePhase(configMap, item, status) { + default: + return syncStatus(configMap, status) + case appsv1alpha1.CPendingPhase, + appsv1alpha1.CMergeFailedPhase: + return syncImpl(fetcher, item, status, synComponent, revision, configSpec) + case appsv1alpha1.CCreatingPhase: + return nil + } }, - SyncStatus: syncStatus, + Status: status, } } -func syncStatus(fetcher *Task, status *appsv1alpha1.ConfigurationItemDetailStatus) (err error) { - err = fetcher.ConfigMap(status.Name).Complete() +func syncImpl(fetcher *Task, + item appsv1alpha1.ConfigurationItemDetail, + status *appsv1alpha1.ConfigurationItemDetailStatus, + component *component.SynthesizedComponent, + revision string, + configSpec *appsv1alpha1.ComponentConfigSpec) (err error) { + err = configuration.NewReconcilePipeline(configuration.ReconcileCtx{ + ResourceCtx: fetcher.ResourceCtx, + Cluster: fetcher.ClusterObj, + ClusterVer: fetcher.ClusterVerObj, + Component: component, + PodSpec: component.PodSpec, + }, item, status, configSpec). + ConfigMap(item.Name). + ConfigConstraints(configSpec.ConfigConstraintRef). + PrepareForTemplate(). + RerenderTemplate(). + ApplyParameters(). + UpdateConfigVersion(revision). + Sync(). + Complete() if err != nil { - return + status.Phase = appsv1alpha1.CMergeFailedPhase + } else { + status.Phase = appsv1alpha1.CMergedPhase } + return +} - annotations := fetcher.ConfigMapObj.GetAnnotations() +func syncStatus(configMap *corev1.ConfigMap, status *appsv1alpha1.ConfigurationItemDetailStatus) (err error) { + annotations := configMap.GetAnnotations() // status.CurrentRevision = GetCurrentRevision(annotations) revisions := RetrieveRevision(annotations) if len(revisions) == 0 { diff --git a/controllers/apps/operations/reconfigure.go b/controllers/apps/operations/reconfigure.go index c0a978c6070..a88ea5c3872 100644 --- a/controllers/apps/operations/reconfigure.go +++ b/controllers/apps/operations/reconfigure.go @@ -28,7 +28,6 @@ import ( appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" "github.com/apecloud/kubeblocks/internal/configuration/core" - "github.com/apecloud/kubeblocks/internal/controller/configuration" intctrlutil "github.com/apecloud/kubeblocks/internal/controllerutil" ) @@ -216,15 +215,11 @@ func (r *reconfigureAction) syncReconfigureOperatorStatus(ctx intctrlutil.Reques } item := fetcher.ConfigurationObj.Spec.GetConfigurationItem(configSpec.Name) - status := fetcher.ConfigurationObj.Status.GetItemStatus(configSpec.Name) - if status == nil || item == nil { + if item == nil { return appsv1alpha1.OpsRunningPhase, nil } - if !configuration.IsApplyConfigChanged(fetcher.ConfigMapObj, *item) { - return appsv1alpha1.OpsRunningPhase, nil - } - switch status.Phase { + switch intctrlutil.GetConfigSpecReconcilePhase(fetcher.ConfigMapObj, *item, fetcher.ConfigurationObj.Status.GetItemStatus(configSpec.Name)) { default: return appsv1alpha1.OpsRunningPhase, nil case appsv1alpha1.CFailedAndPausePhase: diff --git a/deploy/helm/crds/apps.kubeblocks.io_configurations.yaml b/deploy/helm/crds/apps.kubeblocks.io_configurations.yaml index 627422ccfe9..7dbc26db996 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_configurations.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_configurations.yaml @@ -310,6 +310,7 @@ spec: phase: description: phase is status of configurationItem. enum: + - Creating - Init - Running - Pending diff --git a/internal/controller/configuration/pipeline.go b/internal/controller/configuration/pipeline.go index 2a0e47e8035..cdc159c093b 100644 --- a/internal/controller/configuration/pipeline.go +++ b/internal/controller/configuration/pipeline.go @@ -20,8 +20,6 @@ along with this program. If not, see . package configuration import ( - "encoding/json" - "reflect" "strconv" corev1 "k8s.io/api/core/v1" @@ -257,7 +255,7 @@ func (p *updatePipeline) isDone() bool { func (p *updatePipeline) PrepareForTemplate() *updatePipeline { buildTemplate := func() (err error) { - p.reconcile = !IsApplyConfigChanged(p.ConfigMapObj, p.item) + p.reconcile = !intctrlutil.IsApplyConfigChanged(p.ConfigMapObj, p.item) if p.isDone() { return } @@ -272,23 +270,6 @@ func (p *updatePipeline) PrepareForTemplate() *updatePipeline { return p.Wrap(buildTemplate) } -func IsApplyConfigChanged(cm *corev1.ConfigMap, item appsv1alpha1.ConfigurationItemDetail) bool { - if cm == nil { - return false - } - - lastAppliedVersion, ok := cm.Annotations[constant.ConfigAppliedVersionAnnotationKey] - if !ok { - return false - } - var target appsv1alpha1.ConfigurationItemDetail - if err := json.Unmarshal([]byte(lastAppliedVersion), &target); err != nil { - return false - } - - return reflect.DeepEqual(target, item) -} - func (p *updatePipeline) ConfigSpec() *appsv1alpha1.ComponentConfigSpec { return p.configSpec } @@ -310,7 +291,7 @@ func (p *updatePipeline) RerenderTemplate() *updatePipeline { if p.isDone() { return } - if needRerender(p.ConfigMapObj, p.item) { + if intctrlutil.IsRerender(p.ConfigMapObj, p.item) { p.newCM, err = p.renderWrapper.rerenderConfigTemplate(p.ctx.Cluster, p.ctx.Component, *p.configSpec, &p.item) } else { p.newCM = p.ConfigMapObj.DeepCopy() @@ -409,18 +390,3 @@ func (p *updatePipeline) SyncStatus() *updatePipeline { return }) } - -func needRerender(obj *corev1.ConfigMap, item appsv1alpha1.ConfigurationItemDetail) bool { - if obj == nil { - return true - } - if item.Version == "" { - return false - } - - version, ok := obj.Annotations[constant.CMConfigurationTemplateVersion] - if !ok || version != item.Version { - return true - } - return false -} diff --git a/internal/controllerutil/config_util.go b/internal/controllerutil/config_util.go index c524365a3ac..0052dd066d5 100644 --- a/internal/controllerutil/config_util.go +++ b/internal/controllerutil/config_util.go @@ -21,6 +21,8 @@ package controllerutil import ( "context" + "encoding/json" + "reflect" "github.com/StudioSol/set" appsv1 "k8s.io/api/apps/v1" @@ -32,6 +34,7 @@ import ( "github.com/apecloud/kubeblocks/internal/configuration/core" "github.com/apecloud/kubeblocks/internal/configuration/util" "github.com/apecloud/kubeblocks/internal/configuration/validate" + "github.com/apecloud/kubeblocks/internal/constant" ) type ConfigEventContext struct { @@ -116,3 +119,50 @@ func fromUpdatedConfig(m map[string]string, sets *set.LinkedHashSetString) map[s } return r } + +// IsApplyConfigChanged checks if the configuration is changed +func IsApplyConfigChanged(configMap *corev1.ConfigMap, item v1alpha1.ConfigurationItemDetail) bool { + if configMap == nil { + return false + } + + lastAppliedVersion, ok := configMap.Annotations[constant.ConfigAppliedVersionAnnotationKey] + if !ok { + return false + } + var target v1alpha1.ConfigurationItemDetail + if err := json.Unmarshal([]byte(lastAppliedVersion), &target); err != nil { + return false + } + + return reflect.DeepEqual(target, item) +} + +// IsRerender checks if the configuration template is changed +func IsRerender(configMap *corev1.ConfigMap, item v1alpha1.ConfigurationItemDetail) bool { + if configMap == nil { + return true + } + if item.Version == "" { + return false + } + + version, ok := configMap.Annotations[constant.CMConfigurationTemplateVersion] + if !ok || version != item.Version { + return true + } + return false +} + +// GetConfigSpecReconcilePhase gets the configuration phase +func GetConfigSpecReconcilePhase(configMap *corev1.ConfigMap, + item v1alpha1.ConfigurationItemDetail, + status *v1alpha1.ConfigurationItemDetailStatus) v1alpha1.ConfigurationPhase { + if status == nil || status.Phase == "" { + return v1alpha1.CCreatingPhase + } + if !IsApplyConfigChanged(configMap, item) { + return v1alpha1.CPendingPhase + } + return status.Phase +} diff --git a/internal/controllerutil/config_util_test.go b/internal/controllerutil/config_util_test.go index 23edc80ba64..7d91f33540d 100644 --- a/internal/controllerutil/config_util_test.go +++ b/internal/controllerutil/config_util_test.go @@ -28,10 +28,13 @@ import ( . "github.com/onsi/gomega" "github.com/StudioSol/set" + corev1 "k8s.io/api/core/v1" "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" "github.com/apecloud/kubeblocks/internal/configuration/core" cfgutil "github.com/apecloud/kubeblocks/internal/configuration/util" + "github.com/apecloud/kubeblocks/internal/constant" + "github.com/apecloud/kubeblocks/internal/controller/builder" testapps "github.com/apecloud/kubeblocks/internal/testutil/apps" testutil "github.com/apecloud/kubeblocks/internal/testutil/k8s" "github.com/apecloud/kubeblocks/test/testdata" @@ -81,6 +84,134 @@ func TestFromUpdatedConfig(t *testing.T) { } } +func TestIsRerender(t *testing.T) { + type args struct { + cm *corev1.ConfigMap + item v1alpha1.ConfigurationItemDetail + } + tests := []struct { + name string + args args + want bool + }{{ + + name: "test", + args: args{ + cm: nil, + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + }, + }, + want: true, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test").GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + }, + }, + want: false, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test"). + GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + Version: "v1", + }, + }, + want: true, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test"). + AddAnnotations(constant.CMConfigurationTemplateVersion, "v1"). + GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + Version: "v2", + }, + }, + want: true, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test"). + AddAnnotations(constant.CMConfigurationTemplateVersion, "v1"). + GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + Version: "v1", + }, + }, + want: false, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsRerender(tt.args.cm, tt.args.item); got != tt.want { + t.Errorf("IsRerender() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetConfigSpecReconcilePhase(t *testing.T) { + type args struct { + cm *corev1.ConfigMap + item v1alpha1.ConfigurationItemDetail + status *v1alpha1.ConfigurationItemDetailStatus + } + tests := []struct { + name string + args args + want v1alpha1.ConfigurationPhase + }{{ + name: "test", + args: args{ + cm: nil, + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + }, + }, + want: v1alpha1.CCreatingPhase, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test").GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + }, + status: &v1alpha1.ConfigurationItemDetailStatus{ + Phase: v1alpha1.CInitPhase, + }, + }, + want: v1alpha1.CPendingPhase, + }, { + name: "test", + args: args{ + cm: builder.NewConfigMapBuilder("default", "test"). + AddAnnotations(constant.ConfigAppliedVersionAnnotationKey, `{"name":"test"}`). + GetObject(), + item: v1alpha1.ConfigurationItemDetail{ + Name: "test", + }, + status: &v1alpha1.ConfigurationItemDetailStatus{ + Phase: v1alpha1.CUpgradingPhase, + }, + }, + want: v1alpha1.CUpgradingPhase, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetConfigSpecReconcilePhase(tt.args.cm, tt.args.item, tt.args.status); got != tt.want { + t.Errorf("GetConfigSpecReconcilePhase() = %v, want %v", got, tt.want) + } + }) + } +} + var _ = Describe("config_util", func() { var k8sMockClient *testutil.K8sClientMockHelper