github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/core/reconfigure_util.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 core 21 22 import ( 23 "encoding/json" 24 "reflect" 25 26 corev1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 28 "sigs.k8s.io/controller-runtime/pkg/client" 29 30 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 31 "github.com/1aal/kubeblocks/pkg/configuration/util" 32 "github.com/1aal/kubeblocks/pkg/constant" 33 ) 34 35 func getUpdateParameterList(cfg *ConfigPatchInfo, trimField string) ([]string, error) { 36 params := make([]string, 0) 37 walkFn := func(parent, cur string, v reflect.Value, fn util.UpdateFn) error { 38 if cur != "" { 39 if parent != "" { 40 cur = parent + "." + cur 41 } 42 params = append(params, cur) 43 } 44 return nil 45 } 46 47 for _, diff := range cfg.UpdateConfig { 48 var err error 49 var updatedParams any 50 if err = json.Unmarshal(diff, &updatedParams); err != nil { 51 return nil, err 52 } 53 if updatedParams, err = trimNestedField(updatedParams, trimField); err != nil { 54 return nil, err 55 } 56 if err := util.UnstructuredObjectWalk(updatedParams, walkFn, true); err != nil { 57 return nil, WrapError(err, "failed to walk params: [%s]", diff) 58 } 59 } 60 return params, nil 61 } 62 63 func trimNestedField(updatedParams any, trimField string) (any, error) { 64 if trimField == "" { 65 return updatedParams, nil 66 } 67 if m, ok := updatedParams.(map[string]interface{}); ok { 68 trimParams, found, err := unstructured.NestedFieldNoCopy(m, trimField) 69 if err != nil { 70 return nil, err 71 } 72 if found { 73 return trimParams, nil 74 } 75 } 76 return updatedParams, nil 77 } 78 79 // ValidateConfigPatch Verifies if the changed parameters have been removed 80 func ValidateConfigPatch(patch *ConfigPatchInfo, formatCfg *appsv1alpha1.FormatterConfig) error { 81 if !patch.IsModify || len(patch.UpdateConfig) == 0 { 82 return nil 83 } 84 85 vParams := GenerateVisualizedParamsList(patch, formatCfg, nil) 86 for _, param := range vParams { 87 for _, p := range param.Parameters { 88 if p.Value == nil { 89 return MakeError("delete config parameter [%s] is not support!", p.Key) 90 } 91 } 92 } 93 return nil 94 } 95 96 // IsUpdateDynamicParameters checks if the changed parameters require a restart 97 func IsUpdateDynamicParameters(cc *appsv1alpha1.ConfigConstraintSpec, cfg *ConfigPatchInfo) (bool, error) { 98 if len(cfg.DeleteConfig) > 0 || len(cfg.AddConfig) > 0 { 99 return false, nil 100 } 101 102 params, err := getUpdateParameterList(cfg, NestedPrefixField(cc.FormatterConfig)) 103 if err != nil { 104 return false, err 105 } 106 updateParams := util.NewSet(params...) 107 108 // if ConfigConstraint has StaticParameters, check updated parameter 109 if len(cc.StaticParameters) > 0 { 110 staticParams := util.NewSet(cc.StaticParameters...) 111 union := util.Union(staticParams, updateParams) 112 if union.Length() > 0 { 113 return false, nil 114 } 115 // if no dynamicParameters is configured, reload is the default behavior 116 if len(cc.DynamicParameters) == 0 { 117 return true, nil 118 } 119 } 120 121 // if ConfigConstraint has DynamicParameter, and all updated params are dynamic 122 if len(cc.DynamicParameters) > 0 { 123 dynamicParams := util.NewSet(cc.DynamicParameters...) 124 diff := util.Difference(updateParams, dynamicParams) 125 return diff.Length() == 0, nil 126 } 127 128 // if the updated parameter is not in list of DynamicParameter, 129 // it is StaticParameter by default, and restart is the default behavior. 130 return false, nil 131 } 132 133 // IsParametersUpdateFromManager checks if the parameters are updated from manager 134 func IsParametersUpdateFromManager(cm *corev1.ConfigMap) bool { 135 annotation := cm.ObjectMeta.Annotations 136 if annotation == nil { 137 return false 138 } 139 v := annotation[constant.KBParameterUpdateSourceAnnotationKey] 140 return v == constant.ReconfigureManagerSource 141 } 142 143 // IsNotUserReconfigureOperation checks if the parameters are updated from operation 144 func IsNotUserReconfigureOperation(cm *corev1.ConfigMap) bool { 145 labels := cm.GetLabels() 146 annotations := cm.GetAnnotations() 147 if labels == nil || annotations == nil { 148 return false 149 } 150 if _, ok := annotations[constant.CMInsEnableRerenderTemplateKey]; !ok { 151 return false 152 } 153 lastReconfigurePhase := labels[constant.CMInsLastReconfigurePhaseKey] 154 if annotations[constant.KBParameterUpdateSourceAnnotationKey] != constant.ReconfigureManagerSource { 155 return false 156 } 157 return lastReconfigurePhase == "" || ReconfigureCreatedPhase == lastReconfigurePhase 158 } 159 160 // SetParametersUpdateSource sets the parameters' update source 161 // manager: parameter only updated from manager 162 // external-template: parameter only updated from template 163 // ops: parameter updated from operation 164 func SetParametersUpdateSource(cm *corev1.ConfigMap, source string) { 165 annotation := cm.GetAnnotations() 166 if annotation == nil { 167 annotation = make(map[string]string) 168 } 169 annotation[constant.KBParameterUpdateSourceAnnotationKey] = source 170 cm.SetAnnotations(annotation) 171 } 172 173 func IsSchedulableConfigResource(object client.Object) bool { 174 var requiredLabels = []string{ 175 constant.AppNameLabelKey, 176 constant.AppInstanceLabelKey, 177 constant.KBAppComponentLabelKey, 178 constant.CMConfigurationTemplateNameLabelKey, 179 constant.CMConfigurationTypeLabelKey, 180 constant.CMConfigurationSpecProviderLabelKey, 181 } 182 183 labels := object.GetLabels() 184 if len(labels) == 0 { 185 return false 186 } 187 for _, label := range requiredLabels { 188 if _, ok := labels[label]; !ok { 189 return false 190 } 191 } 192 return true 193 }