github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/revision.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  	"encoding/json"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  
    28  	corev1 "k8s.io/api/core/v1"
    29  
    30  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    31  	"github.com/1aal/kubeblocks/pkg/configuration/core"
    32  	"github.com/1aal/kubeblocks/pkg/constant"
    33  	intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil"
    34  )
    35  
    36  type ConfigurationRevision struct {
    37  	Revision    int64
    38  	StrRevision string
    39  	Phase       appsv1alpha1.ConfigurationPhase
    40  	Result      intctrlutil.Result
    41  }
    42  
    43  const revisionHistoryLimit = 10
    44  
    45  func GcConfigRevision(configObj *corev1.ConfigMap) {
    46  	revisions := GcRevision(configObj.ObjectMeta.Annotations)
    47  	if len(revisions) > 0 {
    48  		for _, v := range revisions {
    49  			delete(configObj.ObjectMeta.Annotations, core.GenerateRevisionPhaseKey(v.StrRevision))
    50  		}
    51  	}
    52  }
    53  
    54  func GcRevision(annotations map[string]string) []ConfigurationRevision {
    55  	revisions := RetrieveRevision(annotations)
    56  	if len(revisions) <= revisionHistoryLimit {
    57  		return nil
    58  	}
    59  
    60  	return revisions[0 : len(revisions)-revisionHistoryLimit]
    61  }
    62  
    63  func GetLastRevision(annotations map[string]string, revision int64) (ConfigurationRevision, bool) {
    64  	revisions := RetrieveRevision(annotations)
    65  	for i := len(revisions) - 1; i >= 0; i-- {
    66  		if revisions[i].Revision == revision {
    67  			return revisions[i], true
    68  		}
    69  	}
    70  	return ConfigurationRevision{}, false
    71  }
    72  
    73  func RetrieveRevision(annotations map[string]string) []ConfigurationRevision {
    74  	var revisions []ConfigurationRevision
    75  	var revisionPrefix = constant.LastConfigurationRevisionPhase + "-"
    76  
    77  	for key, value := range annotations {
    78  		if !strings.HasPrefix(key, revisionPrefix) {
    79  			continue
    80  		}
    81  		revision, err := parseRevision(strings.TrimPrefix(key, revisionPrefix), value)
    82  		if err == nil {
    83  			revisions = append(revisions, revision)
    84  		}
    85  	}
    86  
    87  	// for sort
    88  	sort.SliceStable(revisions, func(i, j int) bool {
    89  		return revisions[i].Revision < revisions[j].Revision
    90  	})
    91  	return revisions
    92  }
    93  
    94  func parseRevision(revision string, data string) (ConfigurationRevision, error) {
    95  	v, err := strconv.ParseInt(revision, 10, 64)
    96  	if err != nil {
    97  		return ConfigurationRevision{}, err
    98  	}
    99  	result := parseResult(data, revision)
   100  	return ConfigurationRevision{
   101  		StrRevision: revision,
   102  		Revision:    v,
   103  		Phase:       result.Phase,
   104  		Result:      result,
   105  	}, nil
   106  }
   107  
   108  func parseResult(data string, revision string) intctrlutil.Result {
   109  	result := intctrlutil.Result{
   110  		Revision: revision,
   111  	}
   112  	data = strings.TrimSpace(data)
   113  	if data == "" {
   114  		return result
   115  	}
   116  	err := json.Unmarshal([]byte(data), &result)
   117  	if err != nil {
   118  		result.Phase = appsv1alpha1.ConfigurationPhase(data)
   119  	}
   120  	return result
   121  }
   122  
   123  func GetCurrentRevision(annotations map[string]string) string {
   124  	if len(annotations) == 0 {
   125  		return ""
   126  	}
   127  	return annotations[constant.ConfigurationRevision]
   128  }