1
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
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
48 type IPVar struct {
49 Val *string
50 }
51
52
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
63 panic("the string pointer passed into IPVar should not be nil")
64 }
65 *v.Val = s
66 return nil
67 }
68
69
70 func (v *IPVar) String() string {
71 if v.Val == nil {
72 return ""
73 }
74 return *v.Val
75 }
76
77
78 func (v *IPVar) Type() string {
79 return "ip"
80 }
81
82
83 type IPPortVar struct {
84 Val *string
85 }
86
87
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
96 panic("the string pointer passed into IPPortVar should not be nil")
97 }
98
99
100
101 if netutils.ParseIPSloppy(s) != nil {
102 *v.Val = s
103 return nil
104 }
105
106
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
122 func (v *IPPortVar) String() string {
123 if v.Val == nil {
124 return ""
125 }
126 return *v.Val
127 }
128
129
130 func (v *IPPortVar) Type() string {
131 return "ipport"
132 }
133
134
135 type PortRangeVar struct {
136 Val *string
137 }
138
139
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
146 panic("the string pointer passed into PortRangeVar should not be nil")
147 }
148 *v.Val = s
149 return nil
150 }
151
152
153 func (v PortRangeVar) String() string {
154 if v.Val == nil {
155 return ""
156 }
157 return *v.Val
158 }
159
160
161 func (v PortRangeVar) Type() string {
162 return "port-range"
163 }
164
165
166 type ReservedMemoryVar struct {
167 Value *[]kubeletconfig.MemoryReservation
168 initialized bool
169 }
170
171
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
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
256 func (v *ReservedMemoryVar) Type() string {
257 return "reserved-memory"
258 }
259
260
261 type RegisterWithTaintsVar struct {
262 Value *[]v1.Taint
263 }
264
265
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
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
297 func (t RegisterWithTaintsVar) Type() string {
298 return "[]v1.Taint"
299 }
300
View as plain text