Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: incorrect state for reconfiguring operator #5570

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cc43575
chore: add reconfigure status for configmap
sophon-zt Oct 19, 2023
0f16452
chore: sync ops status for reconfiguring progress
sophon-zt Oct 20, 2023
d42d975
fix: no need to update revision of configSpecs that have not changed
sophon-zt Oct 20, 2023
009a54e
chore: add ut
sophon-zt Oct 20, 2023
521bcfc
fix: failed to lint
sophon-zt Oct 20, 2023
726d89e
chore: removed useless code for opsrequest
sophon-zt Oct 20, 2023
1473e8a
fix: clean configuration resource after deleting cluster
sophon-zt Oct 20, 2023
077cb5d
fix: configuration pipeline crash on nil
sophon-zt Oct 20, 2023
a5e8174
fix: failed to ut
sophon-zt Oct 20, 2023
0c7a634
chore: update configuration.status api
sophon-zt Oct 20, 2023
8ec57fd
chore: not update reconfiguring status without reconcile
sophon-zt Oct 20, 2023
908fff3
chore: refine the reconfigure operation code
sophon-zt Oct 20, 2023
0d99687
chore: minor adjust
sophon-zt Oct 21, 2023
8674c39
chore: Removed dependency on cd/cv for reconfiguring operation
sophon-zt Oct 22, 2023
ddf91ca
chore: refine k8sclient mock
sophon-zt Oct 22, 2023
47b7cad
chore: refine doMerge code
sophon-zt Oct 22, 2023
cf9a27f
fix: failed to lint
sophon-zt Oct 23, 2023
d740ebb
chore: adjust typo as recommended by code review
sophon-zt Oct 25, 2023
2fa8cc0
chore: Fast failure when the changed configSpec does not exist
sophon-zt Oct 25, 2023
5fbe5dd
chore: add configuration cr lifecycle (#5600)
sophon-zt Oct 25, 2023
f6be9be
chore: intctrlutil.HandleCRDeletion may cause resources to be rolled …
sophon-zt Oct 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apis/apps/v1alpha1/configuration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,33 @@ type ConfigurationSpec struct {
ConfigItemDetails []ConfigurationItemDetail `json:"configItemDetails,omitempty"`
}

type ReconcileDetail struct {
// policy is the policy of the latest execution.
// +optional
Policy string `json:"policy"`
// execResult is the result of the latest execution.
// +optional
ExecResult string `json:"execResult"`

// currentRevision is the current revision of configurationItem.
// +optional
CurrentRevision string `json:"currentRevision,omitempty"`

// successCount is the number of pods for which configuration changes were successfully executed.
sophon-zt marked this conversation as resolved.
Show resolved Hide resolved
// +kubebuilder:default=-1
// +optional
SucceedCount int32 `json:"succeedCount,omitempty"`

// expectedCount is the number of pods that need to be executed for configuration changes.
// +kubebuilder:default=-1
// +optional
ExpectedCount int32 `json:"expectedCount,omitempty"`

// errMessage is the error message when the configuration change execution fails.
// +optional
ErrMessage string `json:"errMessage,omitempty"`
}

type ConfigurationItemDetailStatus struct {
// name is a config template name.
// +kubebuilder:validation:Required
Expand All @@ -100,6 +127,10 @@ type ConfigurationItemDetailStatus struct {
// message field describes the reasons of abnormal status.
// +optional
Message *string `json:"message,omitempty"`

// reconcileDetail describes the details of the configuration change execution.
// +optional
ReconcileDetail *ReconcileDetail `json:"reconcileDetail,omitempty"`
}

// ConfigurationStatus defines the observed state of Configuration
Expand Down
4 changes: 2 additions & 2 deletions apis/apps/v1alpha1/opsrequest_conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ const (

// condition and event reasons

ReasonReconfigureMerging = "ReconfigureMerging"
ReasonReconfigureMerged = "ReconfigureMerged"
ReasonReconfigurePersisting = "ReconfigurePersisting"
ReasonReconfigurePersisted = "ReconfigurePersisted"
ReasonReconfigureFailed = "ReconfigureFailed"
ReasonReconfigureRestartFailed = "ReconfigureRestartFailed"
ReasonReconfigureRestart = "ReconfigureRestarted"
Expand Down
4 changes: 4 additions & 0 deletions apis/apps/v1alpha1/opsrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ type ConfigurationItemStatus struct {
// +optional
Status string `json:"status,omitempty"`

// message describes the details about this operation.
// +optional
Message string `json:"message,omitempty"`

// succeedCount describes the number of successful reconfiguring.
// +kubebuilder:default=0
// +optional
Expand Down
20 changes: 20 additions & 0 deletions apis/apps/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions config/crd/bases/apps.kubeblocks.io_configurations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,37 @@ spec:
- FailedAndRetry
- Finished
type: string
reconcileDetail:
description: reconcileDetail describes the details of the configuration
change execution.
properties:
currentRevision:
description: currentRevision is the current revision of
configurationItem.
type: string
errMessage:
description: errMessage is the error message when the configuration
change execution fails.
type: string
execResult:
description: execResult is the result of the latest execution.
type: string
expectedCount:
default: -1
description: expectedCount is the number of pods that need
to be executed for configuration changes.
format: int32
type: integer
policy:
description: policy is the policy of the latest execution.
type: string
succeedCount:
default: -1
description: successCount is the number of pods for which
configuration changes were successfully executed.
format: int32
type: integer
type: object
updateRevision:
description: updateRevision is the update revision of configurationItem.
type: string
Expand Down
3 changes: 3 additions & 0 deletions config/crd/bases/apps.kubeblocks.io_opsrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,9 @@ spec:
description: lastStatus describes the last status for the
reconfiguring controller.
type: string
message:
description: message describes the details about this operation.
type: string
name:
description: name is a config template name.
maxLength: 63
Expand Down
1 change: 1 addition & 0 deletions controllers/apps/components/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ var _ = Describe("Component", func() {
AddVolumeClaimTemplate(testapps.DataVolumeName, testapps.NewPVCSpec(defaultVolumeSize)).
GetObject()

clusterObj.SetUID(types.UID(clusterObj.Name))
reqCtx = intctrlutil.RequestCtx{Ctx: ctx, Log: logger, Recorder: recorder}
}

Expand Down
71 changes: 64 additions & 7 deletions controllers/apps/configuration/config_annotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package configuration

import (
"encoding/json"
"fmt"
"strconv"

corev1 "k8s.io/api/core/v1"
Expand All @@ -34,6 +35,49 @@ import (
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
)

type options = func(*intctrlutil.Result)

func reconciled(status ReturnedStatus, policy string, phase appsv1alpha1.ConfigurationPhase, options ...options) intctrlutil.Result {
result := intctrlutil.Result{
Policy: policy,
Phase: phase,
ExecResult: string(status.Status),
SucceedCount: status.SucceedCount,
ExpectedCount: status.ExpectedCount,
Retry: true,
}
for _, option := range options {
option(&result)
}
return result
}

func unReconciled(phase appsv1alpha1.ConfigurationPhase, revision string, message string) intctrlutil.Result {
return intctrlutil.Result{
Phase: phase,
Revision: revision,
Message: message,
SucceedCount: core.NotStarted,
ExpectedCount: core.Unconfirmed,
Failed: false,
Retry: false,
}
}

func isReconciledResult(result intctrlutil.Result) bool {
return result.ExecResult != "" && result.Policy != ""
}

func withFailed(err error, retry bool) options {
return func(result *intctrlutil.Result) {
result.Retry = retry
if err != nil {
result.Failed = true
result.Message = err.Error()
}
}
}

func checkEnableCfgUpgrade(object client.Object) bool {
// check user's upgrade switch
// config.kubeblocks.io/disable-reconfigure = "false"
Expand All @@ -51,7 +95,11 @@ func checkEnableCfgUpgrade(object client.Object) bool {
return true
}

func updateConfigPhase(cli client.Client, ctx intctrlutil.RequestCtx, config *corev1.ConfigMap, phase appsv1alpha1.ConfigurationPhase, failed bool, retry bool) (ctrl.Result, error) {
func updateConfigPhase(cli client.Client, ctx intctrlutil.RequestCtx, config *corev1.ConfigMap, phase appsv1alpha1.ConfigurationPhase, message string) (ctrl.Result, error) {
return updateConfigPhaseWithResult(cli, ctx, config, unReconciled(phase, "", message))
}

func updateConfigPhaseWithResult(cli client.Client, ctx intctrlutil.RequestCtx, config *corev1.ConfigMap, result intctrlutil.Result) (ctrl.Result, error) {
revision, ok := config.ObjectMeta.Annotations[constant.ConfigurationRevision]
if !ok || revision == "" {
return intctrlutil.Reconciled()
Expand All @@ -62,16 +110,21 @@ func updateConfigPhase(cli client.Client, ctx intctrlutil.RequestCtx, config *co
config.ObjectMeta.Annotations = map[string]string{}
}

if failed {
if result.Failed {
config.ObjectMeta.Annotations[constant.DisableUpgradeInsConfigurationAnnotationKey] = strconv.FormatBool(true)
}

GcConfigRevision(config)
config.ObjectMeta.Annotations[core.GenerateRevisionPhaseKey(revision)] = string(phase)
if _, ok := config.ObjectMeta.Annotations[core.GenerateRevisionPhaseKey(revision)]; !ok || isReconciledResult(result) {
result.Revision = revision
b, _ := json.Marshal(result)
config.ObjectMeta.Annotations[core.GenerateRevisionPhaseKey(revision)] = string(b)
}

if err := cli.Patch(ctx.Ctx, config, patch); err != nil {
return intctrlutil.RequeueWithError(err, ctx.Log, "")
}
if retry {
if result.Retry {
return intctrlutil.RequeueAfter(ConfigReconcileInterval, ctx.Log, "")
}
return intctrlutil.Reconciled()
Expand All @@ -88,14 +141,14 @@ func checkAndApplyConfigsChanged(client client.Client, ctx intctrlutil.RequestCt

lastConfig, ok := annotations[constant.LastAppliedConfigAnnotationKey]
if !ok {
return updateAppliedConfigs(client, ctx, cm, configData, core.ReconfigureCreatedPhase)
return updateAppliedConfigs(client, ctx, cm, configData, core.ReconfigureCreatedPhase, nil)
}

return lastConfig == string(configData), nil
}

// updateAppliedConfigs updates hash label and last applied config
func updateAppliedConfigs(cli client.Client, ctx intctrlutil.RequestCtx, config *corev1.ConfigMap, configData []byte, reconfigurePhase string) (bool, error) {
func updateAppliedConfigs(cli client.Client, ctx intctrlutil.RequestCtx, config *corev1.ConfigMap, configData []byte, reconfigurePhase string, result *intctrlutil.Result) (bool, error) {

patch := client.MergeFrom(config.DeepCopy())
if config.ObjectMeta.Annotations == nil {
Expand All @@ -104,7 +157,11 @@ func updateAppliedConfigs(cli client.Client, ctx intctrlutil.RequestCtx, config

GcConfigRevision(config)
if revision, ok := config.ObjectMeta.Annotations[constant.ConfigurationRevision]; ok && revision != "" {
config.ObjectMeta.Annotations[core.GenerateRevisionPhaseKey(revision)] = string(appsv1alpha1.CFinishedPhase)
if result == nil {
result = util.ToPointer(unReconciled(appsv1alpha1.CFinishedPhase, "", fmt.Sprintf("phase: %s", reconfigurePhase)))
}
b, _ := json.Marshal(result)
config.ObjectMeta.Annotations[core.GenerateRevisionPhaseKey(revision)] = string(b)
}
config.ObjectMeta.Annotations[constant.LastAppliedConfigAnnotationKey] = string(configData)
hash, err := util.ComputeHash(config.Data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ func (r *ConfigurationReconciler) runTasks(taskCtx TaskContext, tasks []Task) (e
patch := client.MergeFrom(configuration.DeepCopy())
revision := strconv.FormatInt(configuration.GetGeneration(), 10)
for _, task := range tasks {
task.Status.UpdateRevision = revision
if err := task.Do(taskCtx.fetcher, synthesizedComp, revision); err != nil {
errs = append(errs, err)
continue
Expand Down
5 changes: 3 additions & 2 deletions controllers/apps/configuration/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ func mockConfigResource() (*corev1.ConfigMap, *appsv1alpha1.ConfigConstraint) {
constant.CMConfigurationSpecProviderLabelKey, configSpecName,
constant.CMConfigurationTypeLabelKey, constant.ConfigInstanceType,
),
testapps.WithAnnotations(constant.KBParameterUpdateSourceAnnotationKey,
constant.ReconfigureManagerSource,
testapps.WithAnnotations(
constant.KBParameterUpdateSourceAnnotationKey, constant.ReconfigureManagerSource,
constant.ConfigurationRevision, "1",
constant.CMInsEnableRerenderTemplateKey, "true"))

By("Create a config constraint obj")
Expand Down
12 changes: 11 additions & 1 deletion controllers/apps/configuration/reconcile_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,16 @@ func syncImpl(fetcher *Task,
UpdateConfigVersion(revision).
Sync().
Complete()

if err != nil {
status.Message = cfgutil.ToPointer(err.Error())
status.Phase = appsv1alpha1.CMergeFailedPhase
} else {
status.Message = nil
status.Phase = appsv1alpha1.CMergedPhase
}
return
status.UpdateRevision = revision
return err
}

func syncStatus(configMap *corev1.ConfigMap, status *appsv1alpha1.ConfigurationItemDetailStatus) (err error) {
Expand Down Expand Up @@ -130,5 +132,13 @@ func updateLastDoneRevision(revision ConfigurationRevision, status *appsv1alpha1
func updateRevision(revision ConfigurationRevision, status *appsv1alpha1.ConfigurationItemDetailStatus) {
if revision.StrRevision == status.UpdateRevision {
status.Phase = revision.Phase
status.ReconcileDetail = &appsv1alpha1.ReconcileDetail{
CurrentRevision: revision.StrRevision,
Policy: revision.Result.Policy,
SucceedCount: revision.Result.SucceedCount,
ExpectedCount: revision.Result.ExpectedCount,
ExecResult: revision.Result.ExecResult,
ErrMessage: revision.Result.Message,
}
}
}
Loading