github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/unstructured/redis_config.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 unstructured 21 22 import ( 23 "bytes" 24 "math" 25 "strconv" 26 "strings" 27 28 "github.com/StudioSol/set" 29 "github.com/spf13/cast" 30 31 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 32 ) 33 34 type redisConfig struct { 35 name string 36 lex *Lexer 37 38 // parameters map[string]string 39 } 40 41 func init() { 42 CfgObjectRegistry().RegisterConfigCreator(appsv1alpha1.RedisCfg, func(name string) ConfigObject { 43 return &redisConfig{name: name} 44 }) 45 } 46 47 func (r *redisConfig) Update(key string, value any) error { 48 return r.setString(key, cast.ToString(value)) 49 } 50 51 func (r *redisConfig) RemoveKey(key string) error { 52 keys := strings.Split(key, " ") 53 v := r.GetItem(keys) 54 if v != nil { 55 r.lex.removeParameter(v) 56 } 57 return nil 58 } 59 60 func (r *redisConfig) setString(key string, value string) error { 61 keys := strings.Split(key, " ") 62 v := r.GetItem(keys) 63 lineNo := math.MaxInt32 64 if v != nil { 65 lineNo = v.LineNo 66 r.lex.removeParameter(v) 67 } 68 keys = append(keys, value) 69 t, err := r.lex.parseParameter(strings.Join(keys, " "), lineNo) 70 if err == nil { 71 if v != nil { 72 t.Comments = v.Comments 73 } 74 r.lex.appendValidParameter(t, lineNo) 75 } 76 return err 77 } 78 79 func matchSubKeys(keys []string, it Item) bool { 80 if len(keys) > len(it.Values) { 81 return false 82 } 83 84 for i, k := range keys { 85 if it.Values[i] != k { 86 return false 87 } 88 } 89 return true 90 } 91 92 func (r *redisConfig) Get(key string) interface{} { 93 v, _ := r.GetString(key) 94 return v 95 } 96 97 func (r *redisConfig) GetItem(keys []string) *Item { 98 v := r.lex.getItem(keys[0]) 99 if v == nil { 100 return nil 101 } 102 103 if len(keys) == 1 && len(v) != 1 { 104 return nil 105 } else if len(keys) == 1 { 106 return &v[0] 107 } 108 109 for i := range v { 110 if matchSubKeys(keys, v[i]) { 111 return &v[i] 112 } 113 } 114 return nil 115 } 116 117 func (r *redisConfig) GetString(key string) (string, error) { 118 keys := strings.Split(key, " ") 119 item := r.GetItem(keys) 120 if item == nil { 121 return "", nil 122 } 123 124 res := make([]string, 0) 125 for i := len(keys); i < len(item.Values); i++ { 126 v := item.Values[i] 127 if ContainerEscapeString(v) { 128 res = append(res, strconv.Quote(v)) 129 } else { 130 res = append(res, v) 131 } 132 } 133 return strings.Join(res, " "), nil 134 } 135 136 func (r *redisConfig) GetAllParameters() map[string]interface{} { 137 params := make(map[string]interface{}) 138 for key, param := range r.lex.getAllParams() { 139 if len(param) == 0 { 140 continue 141 } 142 if len(param) == 1 { 143 params[key] = encodeStringValue(param[0], 1) 144 continue 145 } 146 prefix := uniqKeysParameters(param) 147 for _, i := range param { 148 params[encodeMultiKeys(i, prefix)] = encodeStringValue(i, prefix) 149 } 150 } 151 return params 152 } 153 154 func encodeMultiKeys(it Item, prefix int) string { 155 buffer := &bytes.Buffer{} 156 for i := 0; i < prefix && i < len(it.Values); i++ { 157 if i > 0 { 158 buffer.WriteByte(' ') 159 } 160 buffer.WriteString(it.Values[i]) 161 } 162 return buffer.String() 163 } 164 165 func encodeStringValue(param Item, index int) string { 166 buffer := &bytes.Buffer{} 167 for i := index; i < len(param.Values); i++ { 168 v := param.Values[i] 169 if i > index { 170 buffer.WriteByte(' ') 171 } 172 if v == "" || ContainerEscapeString(v) { 173 v = strconv.Quote(v) 174 } 175 buffer.WriteString(v) 176 } 177 return buffer.String() 178 } 179 180 func uniqKeysParameters(its []Item) int { 181 maxPrefix := len(its[0].Values) 182 for i := 2; i < maxPrefix; i++ { 183 if !hasPrefixKey(its, i) { 184 return i 185 } 186 } 187 return maxPrefix 188 } 189 190 func hasPrefixKey(its []Item, prefix int) bool { 191 keys := set.NewLinkedHashSetString() 192 for _, i := range its { 193 prefixKeys := strings.Join(i.Values[0:prefix], " ") 194 if keys.InArray(prefixKeys) { 195 return true 196 } 197 keys.Add(prefixKeys) 198 } 199 return false 200 } 201 202 func (r *redisConfig) SubConfig(key string) ConfigObject { 203 return nil 204 } 205 206 func (r *redisConfig) Marshal() (string, error) { 207 if r.lex.empty() { 208 return "", nil 209 } 210 if !r.lex.isUpdated { 211 return r.lex.toString(), nil 212 } 213 214 out := &bytes.Buffer{} 215 for i, param := range r.lex.sortParameters() { 216 if i > 0 { 217 out.WriteByte('\n') 218 } 219 if err := encodeParamItem(param, out); err != nil { 220 return "", err 221 } 222 } 223 return out.String(), nil 224 } 225 226 func encodeParamItem(param Item, out *bytes.Buffer) error { 227 for _, co := range param.Comments { 228 out.WriteString(co) 229 out.WriteByte('\n') 230 } 231 for i, v := range param.Values { 232 if i > 0 { 233 out.WriteByte(' ') 234 } 235 if v == "" || ContainerEscapeString(v) { 236 v = strconv.Quote(v) 237 } 238 out.WriteString(v) 239 } 240 return nil 241 } 242 243 func (r *redisConfig) Unmarshal(str string) error { 244 r.lex = &Lexer{} 245 return r.lex.Load(str) 246 }