github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/sync_upgrade_policy.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package configuration
    21  
    22  import (
    23  	"fmt"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/labels"
    28  
    29  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    30  	"github.com/1aal/kubeblocks/pkg/configuration/core"
    31  	podutil "github.com/1aal/kubeblocks/pkg/controllerutil"
    32  )
    33  
    34  type syncPolicy struct {
    35  }
    36  
    37  func init() {
    38  	RegisterPolicy(appsv1alpha1.OperatorSyncUpdate, &syncPolicy{})
    39  }
    40  
    41  func (o *syncPolicy) GetPolicyName() string {
    42  	return string(appsv1alpha1.OperatorSyncUpdate)
    43  }
    44  
    45  func (o *syncPolicy) Upgrade(params reconfigureParams) (ReturnedStatus, error) {
    46  	configPatch := params.ConfigPatch
    47  	if !configPatch.IsModify {
    48  		return makeReturnedStatus(ESNone), nil
    49  	}
    50  
    51  	updatedParameters := getOnlineUpdateParams(configPatch, params.ConfigConstraint.FormatterConfig)
    52  	if len(updatedParameters) == 0 {
    53  		return makeReturnedStatus(ESNone), nil
    54  	}
    55  
    56  	var funcs RollingUpgradeFuncs
    57  	switch params.WorkloadType() {
    58  	default:
    59  		return makeReturnedStatus(ESNotSupport), core.MakeError("not support component workload type[%s]", params.WorkloadType())
    60  	case appsv1alpha1.Stateless:
    61  		funcs = GetDeploymentRollingUpgradeFuncs()
    62  	case appsv1alpha1.Consensus:
    63  		funcs = GetConsensusRollingUpgradeFuncs()
    64  	case appsv1alpha1.Stateful:
    65  		funcs = GetStatefulSetRollingUpgradeFuncs()
    66  	case appsv1alpha1.Replication:
    67  		funcs = GetReplicationRollingUpgradeFuncs()
    68  	}
    69  
    70  	pods, err := funcs.GetPodsFunc(params)
    71  	if err != nil {
    72  		return makeReturnedStatus(ESFailedAndRetry), err
    73  	}
    74  	return sync(params, updatedParameters, pods, funcs)
    75  }
    76  
    77  func matchLabel(pods []corev1.Pod, selector *metav1.LabelSelector) ([]corev1.Pod, error) {
    78  	var result []corev1.Pod
    79  
    80  	match, err := metav1.LabelSelectorAsSelector(selector)
    81  	if err != nil {
    82  		return nil, core.WrapError(err, "failed to convert selector: %v", selector)
    83  	}
    84  	for _, pod := range pods {
    85  		if match.Matches(labels.Set(pod.Labels)) {
    86  			result = append(result, pod)
    87  		}
    88  	}
    89  	return result, nil
    90  }
    91  
    92  func sync(params reconfigureParams, updatedParameters map[string]string, pods []corev1.Pod, funcs RollingUpgradeFuncs) (ReturnedStatus, error) {
    93  	var (
    94  		r        = ESNone
    95  		total    = int32(len(pods))
    96  		replicas = int32(params.getTargetReplicas())
    97  		progress = core.NotStarted
    98  
    99  		err         error
   100  		ctx         = params.Ctx.Ctx
   101  		configKey   = params.getConfigKey()
   102  		versionHash = params.getTargetVersionHash()
   103  	)
   104  
   105  	if params.ConfigConstraint.Selector != nil {
   106  		pods, err = matchLabel(pods, params.ConfigConstraint.Selector)
   107  	}
   108  	if err != nil {
   109  		return makeReturnedStatus(ESFailedAndRetry), err
   110  	}
   111  	if len(pods) == 0 {
   112  		params.Ctx.Log.Info(fmt.Sprintf("no pods to update, and retry, selector: %s", params.ConfigConstraint.Selector.String()))
   113  		return makeReturnedStatus(ESRetry), nil
   114  	}
   115  
   116  	requireUpdatedCount := int32(len(pods))
   117  	for _, pod := range pods {
   118  		params.Ctx.Log.V(1).Info(fmt.Sprintf("sync pod: %s", pod.Name))
   119  		if podutil.IsMatchConfigVersion(&pod, configKey, versionHash) {
   120  			progress++
   121  			continue
   122  		}
   123  		if !podutil.PodIsReady(&pod) {
   124  			continue
   125  		}
   126  		err = funcs.OnlineUpdatePodFunc(&pod, ctx, params.ReconfigureClientFactory, params.ConfigSpecName, updatedParameters)
   127  		if err != nil {
   128  			return makeReturnedStatus(ESFailedAndRetry), err
   129  		}
   130  		err = updatePodLabelsWithConfigVersion(&pod, configKey, versionHash, params.Client, ctx)
   131  		if err != nil {
   132  			return makeReturnedStatus(ESFailedAndRetry), err
   133  		}
   134  		progress++
   135  	}
   136  
   137  	if requireUpdatedCount != progress || replicas != total {
   138  		r = ESRetry
   139  	}
   140  	return makeReturnedStatus(r, withExpected(requireUpdatedCount), withSucceed(progress)), nil
   141  }
   142  
   143  func getOnlineUpdateParams(configPatch *core.ConfigPatchInfo, formatConfig *appsv1alpha1.FormatterConfig) map[string]string {
   144  	r := make(map[string]string)
   145  	parameters := core.GenerateVisualizedParamsList(configPatch, formatConfig, nil)
   146  	for _, key := range parameters {
   147  		if key.UpdateType == core.UpdatedType {
   148  			for _, p := range key.Parameters {
   149  				if p.Value != nil {
   150  					r[p.Key] = *p.Value
   151  				}
   152  			}
   153  		}
   154  	}
   155  	return r
   156  }