k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/util/util.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "math/rand" 24 "strconv" 25 "time" 26 27 "k8s.io/apimachinery/pkg/labels" 28 ) 29 30 // ErrKeyNotFound is returned when key doesn't exists in a map. 31 type ErrKeyNotFound struct { 32 key string 33 } 34 35 // Erros is an error interface implementation. 36 func (e *ErrKeyNotFound) Error() string { 37 return fmt.Sprintf("key %s not found", e.key) 38 } 39 40 // IsErrKeyNotFound returns true only if error type is ErrKeyNotFound. 41 func IsErrKeyNotFound(err error) bool { 42 _, isErrKeyNotFound := err.(*ErrKeyNotFound) 43 return isErrKeyNotFound 44 } 45 46 // ToStruct converts map[string]interface{} to standard object (e.g. struct). It preserves fields that are not set in dict. 47 func ToStruct(dict map[string]interface{}, out interface{}) error { 48 output := &bytes.Buffer{} 49 if err := json.NewEncoder(output).Encode(dict); err != nil { 50 return fmt.Errorf("error encoding data: %w", err) 51 } 52 if err := json.NewDecoder(output).Decode(out); err != nil { 53 return fmt.Errorf("error decoding data: %w", err) 54 } 55 return nil 56 } 57 58 // GetString tries to return value from map cast to string type. If value doesn't exist, error is returned. 59 func GetString(dict map[string]interface{}, key string) (string, error) { 60 return getString(dict, key) 61 } 62 63 // GetInt tries to return value from map cast to int type. If value doesn't exist, error is returned. 64 func GetInt(dict map[string]interface{}, key string) (int, error) { 65 return getInt(dict, key) 66 } 67 68 // GetFloat64 tries to return value from map cast to float64 type. If value doesn't exist, error is returned. 69 func GetFloat64(dict map[string]interface{}, key string) (float64, error) { 70 return getFloat64(dict, key) 71 } 72 73 // GetDuration tries to return value from map cast to duration type. If value doesn't exist, error is returned. 74 func GetDuration(dict map[string]interface{}, key string) (time.Duration, error) { 75 return getDuration(dict, key) 76 } 77 78 // GetBool tries to return value from map cast to bool type. If value doesn't exist, error is returned. 79 func GetBool(dict map[string]interface{}, key string) (bool, error) { 80 return getBool(dict, key) 81 } 82 83 // GetMap tries to return value from map of type map. If value doesn't exist, error is returned. 84 func GetMap(dict map[string]interface{}, key string) (map[string]interface{}, error) { 85 return getMap(dict, key) 86 } 87 88 // GetMapArray tries to return value from map of type []map. If value doesn't exist, error is returned. 89 func GetMapArray(dict map[string]interface{}, key string) ([]map[string]interface{}, error) { 90 return getMapArray(dict, key) 91 } 92 93 // GetStringArray tries to return value from map cast to a []string, using fmt.Sprintf for elements. If value doesn't exist, error is returned. 94 func GetStringArray(dict map[string]interface{}, key string) ([]string, error) { 95 return getStringArray(dict, key) 96 } 97 98 // GetLabelSelector tries to return value from map parsed as labels.Selector type. If value doesn't exist, error is returned. 99 func GetLabelSelector(dict map[string]interface{}, key string) (*labels.Selector, error) { 100 return getLabelSelector(dict, key) 101 } 102 103 // GetStringOrDefault tries to return value from map cast to string type. If value doesn't exist default value is used. 104 func GetStringOrDefault(dict map[string]interface{}, key string, defaultValue string) (string, error) { 105 value, err := getString(dict, key) 106 if IsErrKeyNotFound(err) { 107 return defaultValue, nil 108 } 109 return value, err 110 } 111 112 // GetIntOrDefault tries to return value from map cast to int type. If value doesn't exist default value is used. 113 func GetIntOrDefault(dict map[string]interface{}, key string, defaultValue int) (int, error) { 114 value, err := getInt(dict, key) 115 if IsErrKeyNotFound(err) { 116 return defaultValue, nil 117 } 118 return value, err 119 } 120 121 // GetFloat64OrDefault tries to return value from map cast to float64 type. If value doesn't exist default value is used. 122 func GetFloat64OrDefault(dict map[string]interface{}, key string, defaultValue float64) (float64, error) { 123 value, err := getFloat64(dict, key) 124 if IsErrKeyNotFound(err) { 125 return defaultValue, nil 126 } 127 return value, err 128 } 129 130 // GetDurationOrDefault tries to return value from map cast to duration type. If value doesn't exist default value is used. 131 func GetDurationOrDefault(dict map[string]interface{}, key string, defaultValue time.Duration) (time.Duration, error) { 132 value, err := getDuration(dict, key) 133 if IsErrKeyNotFound(err) { 134 return defaultValue, nil 135 } 136 return value, err 137 } 138 139 // GetBoolOrDefault tries to return value from map cast to bool type. If value doesn't exist default value is used. 140 func GetBoolOrDefault(dict map[string]interface{}, key string, defaultValue bool) (bool, error) { 141 value, err := getBool(dict, key) 142 if IsErrKeyNotFound(err) { 143 return defaultValue, nil 144 } 145 return value, err 146 } 147 148 func getLabelSelector(dict map[string]interface{}, key string) (*labels.Selector, error) { 149 value, err := getString(dict, key) 150 if err != nil { 151 return nil, err 152 } 153 154 selector, err := labels.Parse(value) 155 if err != nil { 156 return nil, err 157 } 158 159 return &selector, nil 160 } 161 162 func getMap(dict map[string]interface{}, key string) (map[string]interface{}, error) { 163 value, exists := dict[key] 164 if !exists || value == nil { 165 return nil, &ErrKeyNotFound{key} 166 } 167 168 mapValue, ok := value.(map[string]interface{}) 169 if !ok { 170 return nil, fmt.Errorf("type assertion error: %v is not a map", value) 171 } 172 return mapValue, nil 173 } 174 175 func getMapArray(dict map[string]interface{}, key string) ([]map[string]interface{}, error) { 176 value, exists := dict[key] 177 if !exists || value == nil { 178 return nil, &ErrKeyNotFound{key} 179 } 180 181 sliceValue, ok := value.([]interface{}) 182 if !ok { 183 return nil, fmt.Errorf("type assertion error: %v (%T) is not a []map", value, value) 184 } 185 186 var res []map[string]interface{} 187 for _, val := range sliceValue { 188 mapValue, ok := val.(map[string]interface{}) 189 if !ok { 190 return nil, fmt.Errorf("type assertion error: %v is not a map", val) 191 } 192 res = append(res, mapValue) 193 } 194 return res, nil 195 } 196 197 func getStringArray(dict map[string]interface{}, key string) ([]string, error) { 198 value, exists := dict[key] 199 if !exists || value == nil { 200 return nil, &ErrKeyNotFound{key} 201 } 202 203 sliceValue, ok := value.([]interface{}) 204 if !ok { 205 return nil, fmt.Errorf("type assertion error: %v (%T) is not a slice", value, value) 206 } 207 208 var res []string 209 for _, val := range sliceValue { 210 valStr := fmt.Sprintf("%v", val) 211 res = append(res, valStr) 212 } 213 return res, nil 214 } 215 216 func getString(dict map[string]interface{}, key string) (string, error) { 217 value, exists := dict[key] 218 if !exists || value == nil { 219 return "", &ErrKeyNotFound{key} 220 } 221 222 stringValue, ok := value.(string) 223 if !ok { 224 return "", fmt.Errorf("type assertion error: %v is not a string", value) 225 } 226 return stringValue, nil 227 } 228 229 func getInt(dict map[string]interface{}, key string) (int, error) { 230 value, exists := dict[key] 231 if !exists { 232 return 0, &ErrKeyNotFound{key} 233 } 234 235 intValue, ok := value.(int) 236 if ok { 237 return intValue, nil 238 } 239 // Types from interface{} create from json cannot be cast directly to int. 240 floatValue, ok := value.(float64) 241 if ok { 242 return int(floatValue), nil 243 } 244 stringValue, ok := value.(string) 245 if ok { 246 if i, err := strconv.Atoi(stringValue); err != nil { 247 return i, nil 248 } 249 } 250 return 0, fmt.Errorf("type assertion error: %v is not an int", value) 251 } 252 253 func getFloat64(dict map[string]interface{}, key string) (float64, error) { 254 value, exists := dict[key] 255 if !exists { 256 return 0, &ErrKeyNotFound{key} 257 } 258 259 floatValue, ok := value.(float64) 260 if ok { 261 return floatValue, nil 262 } 263 stringValue, ok := value.(string) 264 if ok { 265 if f, err := strconv.ParseFloat(stringValue, 64); err != nil { 266 return f, nil 267 } 268 } 269 return 0, fmt.Errorf("type assertion error: %v is not a float", value) 270 } 271 272 func getDuration(dict map[string]interface{}, key string) (time.Duration, error) { 273 durationString, err := getString(dict, key) 274 if err != nil { 275 return 0, err 276 } 277 278 duration, err := time.ParseDuration(durationString) 279 if err != nil { 280 return 0, fmt.Errorf("parsing duration error: %v", err) 281 } 282 return duration, nil 283 } 284 285 func getBool(dict map[string]interface{}, key string) (bool, error) { 286 value, exists := dict[key] 287 if !exists { 288 return false, &ErrKeyNotFound{key} 289 } 290 291 boolValue, ok := value.(bool) 292 if ok { 293 return boolValue, nil 294 } 295 stringValue, ok := value.(string) 296 if ok { 297 if b, err := strconv.ParseBool(stringValue); err != nil { 298 return b, nil 299 } 300 } 301 return false, fmt.Errorf("type assertion error: %v is not a bool", value) 302 } 303 304 // PrettyPrintJSON converts given data into formatted json. 305 func PrettyPrintJSON(data interface{}) (string, error) { 306 output := &bytes.Buffer{} 307 if err := json.NewEncoder(output).Encode(data); err != nil { 308 return "", fmt.Errorf("building encoder error: %v", err) 309 } 310 formatted := &bytes.Buffer{} 311 if err := json.Indent(formatted, output.Bytes(), "", " "); err != nil { 312 return "", fmt.Errorf("indenting error: %v", err) 313 } 314 return formatted.String(), nil 315 } 316 317 // CopyMap copies values from one map to the other. 318 func CopyMap(src, dest map[string]interface{}) { 319 for k, v := range src { 320 dest[k] = v 321 } 322 } 323 324 // CloneMap returns clone of the provided map. 325 func CloneMap(src map[string]interface{}) map[string]interface{} { 326 m := make(map[string]interface{}) 327 CopyMap(src, m) 328 return m 329 } 330 331 // RandomDNS1123String generates random string of a given length. 332 func RandomDNS1123String(length int) string { 333 characters := []rune("abcdefghijklmnopqrstuvwxyz0123456789") 334 s := make([]rune, length) 335 for i := range s { 336 s[i] = characters[rand.Intn(len(characters))] 337 } 338 return string(s) 339 }