k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/modifier/modifier.go (about) 1 /* 2 Copyright 2020 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 modifier 18 19 import ( 20 "fmt" 21 "reflect" 22 "strconv" 23 "strings" 24 25 "k8s.io/klog/v2" 26 "k8s.io/perf-tests/clusterloader2/api" 27 "k8s.io/perf-tests/clusterloader2/pkg/config" 28 "k8s.io/perf-tests/clusterloader2/pkg/flags" 29 ) 30 31 // Modifier mutates provided test 32 type Modifier interface { 33 ChangeTest(*api.Config) error 34 } 35 36 // InitFlags allows setting configuration with flags 37 func InitFlags(m *config.ModifierConfig) { 38 flags.StringArrayVar(&m.OverwriteTestConfig, "overwrite-test-config", []string{}, "Overwrite test config with specific value, used as parameter1.parameter2=value, for example 'Namespace.Prefix=custom-prefix'") 39 flags.StringArrayVar(&m.SkipSteps, "skip-steps", []string{}, "Name of steps to skip in test") 40 } 41 42 // NewModifier creates new Modifier according to provided configuration 43 func NewModifier(m *config.ModifierConfig) Modifier { 44 return &simpleModifier{overwriteTestConfig: m.OverwriteTestConfig, skipSteps: m.SkipSteps} 45 } 46 47 type simpleModifier struct { 48 overwriteTestConfig []string 49 skipSteps []string 50 } 51 52 // Ensuring that simpleModifier implements Modifier interface 53 var _ Modifier = &simpleModifier{} 54 55 func (m *simpleModifier) ChangeTest(c *api.Config) error { 56 m.modifySkipSteps(c) 57 return m.modifyOverwrite(c) 58 } 59 60 func (m *simpleModifier) modifySkipSteps(c *api.Config) { 61 steps := c.Steps 62 c.Steps = []*api.Step{} 63 for _, s := range steps { 64 ignored := false 65 for _, i := range m.skipSteps { 66 if i == s.Name { 67 ignored = true 68 klog.V(3).Infof("Ignoring step %s", s.Name) 69 break 70 } 71 } 72 if !ignored { 73 c.Steps = append(c.Steps, s) 74 } 75 } 76 } 77 78 func (m *simpleModifier) modifyOverwrite(c *api.Config) error { 79 for _, o := range m.overwriteTestConfig { 80 kv := strings.Split(o, "=") 81 if len(kv) != 2 { 82 return fmt.Errorf("not a key=value pair: '%s'", o) 83 } 84 k, v := kv[0], kv[1] 85 86 parameterPath := strings.Split(k, ".") 87 curValue := reflect.ValueOf(c).Elem() 88 for _, p := range parameterPath { 89 curValue = curValue.FieldByName(p) 90 if !curValue.IsValid() { 91 return fmt.Errorf("cannot overwrite config for key '%s'. Path does not exist", k) 92 } 93 // We want to dereference pointers if any happen along the way 94 if curValue.Kind() == reflect.Ptr { 95 // If path came across ptr to nil, we need to create zero value before dereferencing 96 if curValue.IsNil() { 97 expectedType := curValue.Type().Elem() 98 pointerToZeroValue := reflect.New(expectedType) 99 curValue.Set(pointerToZeroValue) 100 } 101 curValue = curValue.Elem() 102 } 103 } 104 err := m.overwriteValue(curValue, v, k) 105 if err != nil { 106 return err 107 } 108 } 109 return nil 110 } 111 112 func (m *simpleModifier) overwriteValue(node reflect.Value, v, k string) error { 113 switch node.Kind() { 114 case reflect.Bool: 115 boolV, err := strconv.ParseBool(v) 116 if err != nil { 117 return fmt.Errorf("test config overwrite error: Cannot parse '%s' for key '%s' to bool: %v", v, k, err) 118 } 119 klog.V(2).Infof("Setting bool value '%t' for key '%s'", boolV, k) 120 node.SetBool(boolV) 121 case reflect.String: 122 klog.V(2).Infof("Setting string value '%s' for key '%s'", v, k) 123 node.SetString(v) 124 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 125 intV, err := strconv.ParseInt(v, 10, node.Type().Bits()) 126 if err != nil { 127 return fmt.Errorf("test config overwrite error: Cannot parse '%s' for key '%s' to int: %v", v, k, err) 128 } 129 klog.V(2).Infof("Setting int value '%d' for key '%s'", intV, k) 130 node.SetInt(intV) 131 default: 132 return fmt.Errorf("unsupported kind: %v for key %s", node.Kind(), k) 133 } 134 return nil 135 }