knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/configmap/parse.go (about) 1 /* 2 Copyright 2020 The Knative 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 configmap 18 19 import ( 20 "fmt" 21 "strings" 22 "time" 23 24 "k8s.io/apimachinery/pkg/api/resource" 25 "k8s.io/apimachinery/pkg/api/validation" 26 "k8s.io/apimachinery/pkg/types" 27 "k8s.io/apimachinery/pkg/util/sets" 28 "knative.dev/pkg/configmap/parser" 29 ) 30 31 // ParseFunc is a function taking ConfigMap data and applying a parse operation to it. 32 type ParseFunc = parser.ParseFunc 33 34 // AsString passes the value at key through into the target, if it exists. 35 var AsString = parser.As[string] 36 37 // AsBool parses the value at key as a boolean into the target, if it exists. 38 var AsBool = parser.As[bool] 39 40 // AsInt16 parses the value at key as an int16 into the target, if it exists. 41 var AsInt16 = parser.As[int16] 42 43 // AsInt32 parses the value at key as an int32 into the target, if it exists. 44 var AsInt32 = parser.As[int32] 45 46 // AsInt64 parses the value at key as an int64 into the target, if it exists. 47 var AsInt64 = parser.As[int64] 48 49 // AsInt parses the value at key as an int into the target, if it exists. 50 var AsInt = parser.As[int] 51 52 // AsUint16 parses the value at key as an uint16 into the target, if it exists. 53 var AsUint16 = parser.As[uint16] 54 55 // AsUint32 parses the value at key as an uint32 into the target, if it exists. 56 var AsUint32 = parser.As[uint32] 57 58 // AsUint64 parses the value at key as an uint32 into the target, if it exists. 59 var AsUint64 = parser.As[uint32] 60 61 // AsFloat64 parses the value at key as a float64 into the target, if it exists. 62 var AsFloat64 = parser.As[float64] 63 64 // AsDuration parses the value at key as a time.Duration into the target, if it exists. 65 var AsDuration = parser.As[time.Duration] 66 67 // AsStringSet parses the value at key as a sets.Set[string] (split by ',') into the target, if it exists. 68 func AsStringSet(key string, target *sets.Set[string]) ParseFunc { 69 return func(data map[string]string) error { 70 if raw, ok := data[key]; ok { 71 splitted := strings.Split(raw, ",") 72 for i, v := range splitted { 73 splitted[i] = strings.TrimSpace(v) 74 } 75 *target = sets.New[string](splitted...) 76 } 77 return nil 78 } 79 } 80 81 // AsQuantity parses the value at key as a *resource.Quantity into the target, if it exists 82 func AsQuantity(key string, target **resource.Quantity) ParseFunc { 83 return func(data map[string]string) error { 84 if raw, ok := data[key]; ok { 85 val, err := resource.ParseQuantity(raw) 86 if err != nil { 87 return fmt.Errorf("failed to parse %q: %w", key, err) 88 } 89 90 *target = &val 91 } 92 return nil 93 } 94 } 95 96 // AsOptionalNamespacedName parses the value at key as a types.NamespacedName into the target, if it exists 97 // The namespace and name are both required and expected to be valid DNS labels 98 func AsOptionalNamespacedName(key string, target **types.NamespacedName) ParseFunc { 99 return func(data map[string]string) error { 100 if _, ok := data[key]; !ok { 101 return nil 102 } 103 104 *target = &types.NamespacedName{} 105 return AsNamespacedName(key, *target)(data) 106 } 107 } 108 109 // AsNamespacedName parses the value at key as a types.NamespacedName into the target, if it exists 110 // The namespace and name are both required and expected to be valid DNS labels 111 func AsNamespacedName(key string, target *types.NamespacedName) ParseFunc { 112 return func(data map[string]string) error { 113 raw, ok := data[key] 114 if !ok { 115 return nil 116 } 117 118 v := strings.SplitN(raw, string(types.Separator), 3) 119 120 if len(v) != 2 { 121 return fmt.Errorf("failed to parse %q: expected 'namespace/name' format", key) 122 } 123 124 for _, val := range v { 125 if errs := validation.ValidateNamespaceName(val, false); len(errs) > 0 { 126 return fmt.Errorf("failed to parse %q: %s", key, strings.Join(errs, ", ")) 127 } 128 } 129 130 target.Namespace = v[0] 131 target.Name = v[1] 132 133 return nil 134 } 135 } 136 137 // Parse parses the given map using the parser functions passed in. 138 func Parse(data map[string]string, parsers ...ParseFunc) error { 139 for _, parse := range parsers { 140 if err := parse(data); err != nil { 141 return err 142 } 143 } 144 return nil 145 } 146 147 // CollectMapEntriesWithPrefix parses the data into the target as a map[string]string, if it exists. 148 // The map is represented as a list of key-value pairs with a common prefix. 149 func CollectMapEntriesWithPrefix(prefix string, target *map[string]string) ParseFunc { 150 if target == nil { 151 panic("target cannot be nil") 152 } 153 154 return func(data map[string]string) error { 155 for k, v := range data { 156 if strings.HasPrefix(k, prefix) && len(k) > len(prefix)+1 { 157 if *target == nil { 158 m := make(map[string]string, 2) 159 *target = m 160 } 161 (*target)[k[len(prefix)+1: /* remove dot `.` */]] = v 162 } 163 } 164 return nil 165 } 166 }