-
Notifications
You must be signed in to change notification settings - Fork 0
/
parted_bytes_formatters.py
168 lines (141 loc) · 5.52 KB
/
parted_bytes_formatters.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# Copyright 2014, Brian Coca <bcoca@ansible.com>
# Copyright 2017, Ken Celenza <ken@networktocode.com>
# Copyright 2017, Jason Edelman <jason@networktocode.com>
# Copyright 2017, Ansible Project
# Copyright 2020, Adanos
#
# This file is plugin for Ansible
#
# This plugin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This plugin is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with This plugin. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
from ansible.errors import AnsibleFilterError
from ansible.utils.display import Display
from ansible.module_utils.six import iteritems
display = Display()
PARTED_SIZE_RANGES = {
'Yi': 1 << 80,
'Y': 10 ** 24,
'Zi': 1 << 70,
'Z': 10 ** 21,
'Ei': 1 << 60,
'E': 10 ** 18,
'Pi': 1 << 50,
'P': 10 ** 15,
'Ti': 1 << 40,
'T': 10 ** 12,
'Gi': 1 << 30,
'G': 10 ** 9,
'Mi': 1 << 20,
'M': 10 ** 6,
'Ki': 1 << 10,
'K': 10 ** 3,
'B': 1,
}
def parted_human_to_bytes_convert(number, default_unit=None, isbits=False, iskibi=False):
"""Convert number in string format into bytes (ex: '2K' => 2048) or using unit argument.
example: human_to_bytes('10M') <=> human_to_bytes(10, 'M')
"""
regex_search_match = re.search(r'^\s*(\d*\.?\d*)\s*([A-Za-z]+)?', str(number), flags=re.IGNORECASE)
if regex_search_match is None:
raise ValueError("human_to_bytes() can't interpret following string: %s" % str(number))
try:
num = float(regex_search_match.group(1))
except Exception:
raise ValueError("human_to_bytes() can't interpret following number: %s (original input string: %s)" % (regex_search_match.group(1), number))
unit = regex_search_match.group(2)
if unit is None:
unit = default_unit
if unit is None:
''' No unit given, returning raw number '''
return int(round(num))
# Get unit for kilo or kibi
if iskibi:
range_key = unit[:2].capitalize()
else:
range_key = unit[0].capitalize()
try:
limit = PARTED_SIZE_RANGES[range_key]
except Exception:
# Get keys correspoinding to unit type (kilo or kibi)
correct_units = []
for KEY in PARTED_SIZE_RANGES:
if len(KEY) == len(range_key):
correct_units.append(KEY)
raise ValueError("human_to_bytes() failed to convert %s (unit = %s). The suffix must be one of %s" % (number, unit, ", ".join(correct_units)))
# default value
unit_class = 'B'
unit_class_name = 'byte'
# handling bits case
if isbits:
unit_class = 'b'
unit_class_name = 'bit'
# check unit value if more than one character (KB, MB)
if len(unit) > 1:
expect_message = 'expect %s%s or %s' % (range_key, unit_class, range_key)
if range_key == 'B':
expect_message = 'expect %s or %s' % (unit_class, unit_class_name)
if unit_class_name in unit.lower():
pass
elif (iskibi and unit[2] != unit_class) or (not iskibi and unit[1] != unit_class):
raise ValueError("human_to_bytes() failed to convert %s. Value is not a valid string (%s)" % (number, expect_message))
return int(round(num * limit))
def parted_human_to_bytes(size, default_unit=None, isbits=False, iskibi=False):
''' Return bytes count from a human readable string '''
try:
return parted_human_to_bytes_convert(size, default_unit, isbits, iskibi)
except Exception:
raise AnsibleFilterError("human_to_bytes() can't interpret following string: %s" % size)
def parted_bytes_to_human(size, isbits=False, unit=None, iskibi=False, spaceseparator=True):
base = 'Bytes'
if isbits:
base = 'bits'
suffix = ''
separator = ''
if spaceseparator:
separator = ' '
# Get only kilo or kibi units
units = []
for item in iteritems(PARTED_SIZE_RANGES):
if (not iskibi and len(item[0]) == 1) or (iskibi and len(item[0]) == 2):
units.append(item)
for suffix, limit in sorted(units, key=lambda item: -item[1]):
if iskibi:
target_suffix = suffix[:2]
else:
target_suffix = suffix[0]
if (unit is None and size >= limit) or unit is not None and unit.capitalize() == target_suffix:
break
if limit != 1:
suffix += base[0]
else:
suffix = base
return '%.2f%s%s' % (size / limit, separator, suffix)
def parted_human_readable(size, isbits=False, unit=None, iskibi=False, spaceseparator=True):
''' Return a human readable string '''
try:
return parted_bytes_to_human(size, isbits, unit, iskibi, spaceseparator)
except Exception:
raise AnsibleFilterError("human_readable() can't interpret following string: %s" % size)
class FilterModule(object):
''' Ansible size filters for Parted'''
def filters(self):
filters = {
# computer theory
'parted_human_readable': parted_human_readable,
'parted_human_to_bytes': parted_human_to_bytes
}
return filters