codekingpro/portable-devtools
114k
1# Copyright 2019 The Kubernetes Authors.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14from decimal import Decimal, InvalidOperation15 16_EXPONENTS = {17 "n": -3,18 "u": -2,19 "m": -1,20 "K": 1,21 "k": 1,22 "M": 2,23 "G": 3,24 "T": 4,25 "P": 5,26 "E": 6,27}28 29 30def parse_quantity(quantity):31 """32 Parse kubernetes canonical form quantity like 200Mi to a decimal number.33 Supported SI suffixes:34 base1024: Ki | Mi | Gi | Ti | Pi | Ei35 base1000: n | u | m | "" | k | M | G | T | P | E36 37 See https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go38 39 Input:40 quantity: string. kubernetes canonical form quantity41 42 Returns:43 Decimal44 45 Raises:46 ValueError on invalid or unknown input47 """48 if isinstance(quantity, (int, float, Decimal)):49 return Decimal(quantity)50 51 quantity = str(quantity)52 number = quantity53 suffix = None54 if len(quantity) >= 2 and quantity[-1] == "i":55 if quantity[-2] in _EXPONENTS:56 number = quantity[:-2]57 suffix = quantity[-2:]58 elif len(quantity) >= 1 and quantity[-1] in _EXPONENTS:59 number = quantity[:-1]60 suffix = quantity[-1:]61 62 try:63 number = Decimal(number)64 except InvalidOperation:65 raise ValueError("Invalid number format: {}".format(number))66 67 if suffix is None:68 return number69 70 if suffix.endswith("i"):71 base = 102472 elif len(suffix) == 1:73 base = 100074 else:75 raise ValueError("{} has unknown suffix".format(quantity))76 77 # handle SI inconsistency78 if suffix == "ki":79 raise ValueError("{} has unknown suffix".format(quantity))80 81 if suffix[0] not in _EXPONENTS:82 raise ValueError("{} has unknown suffix".format(quantity))83 84 exponent = Decimal(_EXPONENTS[suffix[0]])85 return number * (base ** exponent)86 87 88def format_quantity(quantity_value, suffix, quantize=None) -> str:89 """90 Takes a decimal and produces a string value in kubernetes' canonical quantity form,91 like "200Mi".Users can specify an additional decimal number to quantize the output.92 93 Example - Relatively increase pod memory limits:94 95 # retrieve my_pod96 current_memory: Decimal = parse_quantity(my_pod.spec.containers[0].resources.limits.memory)97 desired_memory = current_memory * 1.298 desired_memory_str = format_quantity(desired_memory, suffix="Gi", quantize=Decimal(1))99 # patch pod with desired_memory_str100 101 'quantize=Decimal(1)' ensures that the result does not contain any fractional digits.102 103 Supported SI suffixes:104 base1024: Ki | Mi | Gi | Ti | Pi | Ei105 base1000: n | u | m | "" | k | M | G | T | P | E106 107 See https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go108 109 Input:110 quantity: Decimal. Quantity as a number which is supposed to converted to a string111 with SI suffix.112 suffix: string. The desired suffix/unit-of-measure of the output string113 quantize: Decimal. Can be used to round/quantize the value before the string114 is returned. Defaults to None.115 116 Returns:117 string. Canonical Kubernetes quantity string containing the SI suffix.118 119 Raises:120 ValueError if the SI suffix is not supported.121 """122 123 if not suffix:124 return str(quantity_value)125 126 if suffix.endswith("i"):127 base = 1024128 elif len(suffix) == 1:129 base = 1000130 else:131 raise ValueError(f"{quantity_value} has unknown suffix")132 133 if suffix == "ki":134 raise ValueError(f"{quantity_value} has unknown suffix")135 136 if suffix[0] not in _EXPONENTS:137 raise ValueError(f"{quantity_value} has unknown suffix")138 139 different_scale = quantity_value / Decimal(base ** _EXPONENTS[suffix[0]])140 if quantize:141 different_scale = different_scale.quantize(quantize)142 return str(different_scale) + suffix143 