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  }