k8s.io/kubernetes@v1.29.3/pkg/util/flag/flags.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 flag 18 19 import ( 20 "fmt" 21 "net" 22 "sort" 23 "strconv" 24 "strings" 25 26 "github.com/spf13/pflag" 27 28 v1 "k8s.io/api/core/v1" 29 "k8s.io/apimachinery/pkg/api/resource" 30 utilnet "k8s.io/apimachinery/pkg/util/net" 31 corev1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" 32 kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" 33 utiltaints "k8s.io/kubernetes/pkg/util/taints" 34 netutils "k8s.io/utils/net" 35 ) 36 37 // TODO(mikedanese): remove these flag wrapper types when we remove command line flags 38 39 var ( 40 _ pflag.Value = &IPVar{} 41 _ pflag.Value = &IPPortVar{} 42 _ pflag.Value = &PortRangeVar{} 43 _ pflag.Value = &ReservedMemoryVar{} 44 _ pflag.Value = &RegisterWithTaintsVar{} 45 ) 46 47 // IPVar is used for validating a command line option that represents an IP. It implements the pflag.Value interface 48 type IPVar struct { 49 Val *string 50 } 51 52 // Set sets the flag value 53 func (v *IPVar) Set(s string) error { 54 if len(s) == 0 { 55 v.Val = nil 56 return nil 57 } 58 if netutils.ParseIPSloppy(s) == nil { 59 return fmt.Errorf("%q is not a valid IP address", s) 60 } 61 if v.Val == nil { 62 // it's okay to panic here since this is programmer error 63 panic("the string pointer passed into IPVar should not be nil") 64 } 65 *v.Val = s 66 return nil 67 } 68 69 // String returns the flag value 70 func (v *IPVar) String() string { 71 if v.Val == nil { 72 return "" 73 } 74 return *v.Val 75 } 76 77 // Type gets the flag type 78 func (v *IPVar) Type() string { 79 return "ip" 80 } 81 82 // IPPortVar is used for validating a command line option that represents an IP and a port. It implements the pflag.Value interface 83 type IPPortVar struct { 84 Val *string 85 } 86 87 // Set sets the flag value 88 func (v *IPPortVar) Set(s string) error { 89 if len(s) == 0 { 90 v.Val = nil 91 return nil 92 } 93 94 if v.Val == nil { 95 // it's okay to panic here since this is programmer error 96 panic("the string pointer passed into IPPortVar should not be nil") 97 } 98 99 // Both IP and IP:port are valid. 100 // Attempt to parse into IP first. 101 if netutils.ParseIPSloppy(s) != nil { 102 *v.Val = s 103 return nil 104 } 105 106 // Can not parse into IP, now assume IP:port. 107 host, port, err := net.SplitHostPort(s) 108 if err != nil { 109 return fmt.Errorf("%q is not in a valid format (ip or ip:port): %v", s, err) 110 } 111 if netutils.ParseIPSloppy(host) == nil { 112 return fmt.Errorf("%q is not a valid IP address", host) 113 } 114 if _, err := netutils.ParsePort(port, true); err != nil { 115 return fmt.Errorf("%q is not a valid number", port) 116 } 117 *v.Val = s 118 return nil 119 } 120 121 // String returns the flag value 122 func (v *IPPortVar) String() string { 123 if v.Val == nil { 124 return "" 125 } 126 return *v.Val 127 } 128 129 // Type gets the flag type 130 func (v *IPPortVar) Type() string { 131 return "ipport" 132 } 133 134 // PortRangeVar is used for validating a command line option that represents a port range. It implements the pflag.Value interface 135 type PortRangeVar struct { 136 Val *string 137 } 138 139 // Set sets the flag value 140 func (v PortRangeVar) Set(s string) error { 141 if _, err := utilnet.ParsePortRange(s); err != nil { 142 return fmt.Errorf("%q is not a valid port range: %v", s, err) 143 } 144 if v.Val == nil { 145 // it's okay to panic here since this is programmer error 146 panic("the string pointer passed into PortRangeVar should not be nil") 147 } 148 *v.Val = s 149 return nil 150 } 151 152 // String returns the flag value 153 func (v PortRangeVar) String() string { 154 if v.Val == nil { 155 return "" 156 } 157 return *v.Val 158 } 159 160 // Type gets the flag type 161 func (v PortRangeVar) Type() string { 162 return "port-range" 163 } 164 165 // ReservedMemoryVar is used for validating a command line option that represents a reserved memory. It implements the pflag.Value interface 166 type ReservedMemoryVar struct { 167 Value *[]kubeletconfig.MemoryReservation 168 initialized bool // set to true after the first Set call 169 } 170 171 // Set sets the flag value 172 func (v *ReservedMemoryVar) Set(s string) error { 173 if v.Value == nil { 174 return fmt.Errorf("no target (nil pointer to *[]MemoryReservation") 175 } 176 177 if s == "" { 178 v.Value = nil 179 return nil 180 } 181 182 if !v.initialized || *v.Value == nil { 183 *v.Value = make([]kubeletconfig.MemoryReservation, 0) 184 v.initialized = true 185 } 186 187 if s == "" { 188 return nil 189 } 190 191 numaNodeReservations := strings.Split(s, ";") 192 for _, reservation := range numaNodeReservations { 193 numaNodeReservation := strings.Split(reservation, ":") 194 if len(numaNodeReservation) != 2 { 195 return fmt.Errorf("the reserved memory has incorrect format, expected numaNodeID:type=quantity[,type=quantity...], got %s", reservation) 196 } 197 memoryTypeReservations := strings.Split(numaNodeReservation[1], ",") 198 if len(memoryTypeReservations) < 1 { 199 return fmt.Errorf("the reserved memory has incorrect format, expected numaNodeID:type=quantity[,type=quantity...], got %s", reservation) 200 } 201 numaNodeID, err := strconv.Atoi(numaNodeReservation[0]) 202 if err != nil { 203 return fmt.Errorf("failed to convert the NUMA node ID, exptected integer, got %s", numaNodeReservation[0]) 204 } 205 206 memoryReservation := kubeletconfig.MemoryReservation{ 207 NumaNode: int32(numaNodeID), 208 Limits: map[v1.ResourceName]resource.Quantity{}, 209 } 210 211 for _, memoryTypeReservation := range memoryTypeReservations { 212 limit := strings.Split(memoryTypeReservation, "=") 213 if len(limit) != 2 { 214 return fmt.Errorf("the reserved limit has incorrect value, expected type=quantatity, got %s", memoryTypeReservation) 215 } 216 217 resourceName := v1.ResourceName(limit[0]) 218 if resourceName != v1.ResourceMemory && !corev1helper.IsHugePageResourceName(resourceName) { 219 return fmt.Errorf("memory type conversion error, unknown type: %q", resourceName) 220 } 221 222 q, err := resource.ParseQuantity(limit[1]) 223 if err != nil { 224 return fmt.Errorf("failed to parse the quantatity, expected quantatity, got %s", limit[1]) 225 } 226 227 memoryReservation.Limits[v1.ResourceName(limit[0])] = q 228 } 229 *v.Value = append(*v.Value, memoryReservation) 230 } 231 return nil 232 } 233 234 // String returns the flag value 235 func (v *ReservedMemoryVar) String() string { 236 if v == nil || v.Value == nil { 237 return "" 238 } 239 240 var slices []string 241 for _, reservedMemory := range *v.Value { 242 var limits []string 243 for resourceName, q := range reservedMemory.Limits { 244 limits = append(limits, fmt.Sprintf("%s=%s", resourceName, q.String())) 245 } 246 247 sort.Strings(limits) 248 slices = append(slices, fmt.Sprintf("%d:%s", reservedMemory.NumaNode, strings.Join(limits, ","))) 249 } 250 251 sort.Strings(slices) 252 return strings.Join(slices, ",") 253 } 254 255 // Type gets the flag type 256 func (v *ReservedMemoryVar) Type() string { 257 return "reserved-memory" 258 } 259 260 // RegisterWithTaintsVar is used for validating a command line option that represents a register with taints. It implements the pflag.Value interface 261 type RegisterWithTaintsVar struct { 262 Value *[]v1.Taint 263 } 264 265 // Set sets the flag value 266 func (t RegisterWithTaintsVar) Set(s string) error { 267 if len(s) == 0 { 268 *t.Value = nil 269 return nil 270 } 271 sts := strings.Split(s, ",") 272 corev1Taints, _, err := utiltaints.ParseTaints(sts) 273 if err != nil { 274 return err 275 } 276 var taints []v1.Taint 277 for _, ct := range corev1Taints { 278 taints = append(taints, v1.Taint{Key: ct.Key, Value: ct.Value, Effect: ct.Effect}) 279 } 280 *t.Value = taints 281 return nil 282 } 283 284 // String returns the flag value 285 func (t RegisterWithTaintsVar) String() string { 286 if len(*t.Value) == 0 { 287 return "" 288 } 289 var taints []string 290 for _, taint := range *t.Value { 291 taints = append(taints, fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect)) 292 } 293 return strings.Join(taints, ",") 294 } 295 296 // Type gets the flag type 297 func (t RegisterWithTaintsVar) Type() string { 298 return "[]v1.Taint" 299 }