...

Source file src/k8s.io/kubernetes/pkg/util/flag/flags.go

Documentation: k8s.io/kubernetes/pkg/util/flag

     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  }
   300  

View as plain text