]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-volume: human_readable_size() refactor 44210/head
authorGuillaume Abrioux <gabrioux@redhat.com>
Tue, 16 Nov 2021 19:32:38 +0000 (20:32 +0100)
committerGuillaume Abrioux <gabrioux@redhat.com>
Fri, 3 Dec 2021 21:57:59 +0000 (22:57 +0100)
This commit refactors the `human_readable_size()` function.

The current implementation has a couple of issues:

in a 'human readable' mindset, I would expect `human_readable_size(1024)` to
return '1.00 KB' instead of '1024.00 KB'.

```
In [1]: from ceph_volume.util.disk import human_readable_size

In [2]: human_readable_size(1024)
Out[2]: '1024.00 B'

In [3]: human_readable_size(1024*1024)
Out[3]: '1024.00 KB'

```

Also, it doesn't support PB unit:

```
In [4]: human_readable_size(1024*1024*1024*1024*1024)
Out[4]: '1024.00 TB'

In [5]: human_readable_size(1024*1024*1024*1024*1024*1024)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-31-0859861661dc> in <module>
----> 1 human_readable_size(1024*1024*1024*1024*1024*1024)

~/GIT/ceph/src/ceph-volume/ceph_volume/util/disk.py in human_readable_size(size)
    640     return "{size:.2f} {suffix}".format(
    641         size=size,
--> 642         suffix=suffixes[suffix_index])
    643
    644

IndexError: list index out of range
```

This commit fixes this.

Fixes: https://tracker.ceph.com/issues/48492
Signed-off-by: Guillaume Abrioux <gabrioux@redhat.com>
(cherry picked from commit 6940856f233f4d365a119eed90ff88fd918f6916)

src/ceph-volume/ceph_volume/tests/util/test_disk.py
src/ceph-volume/ceph_volume/util/disk.py

index 5f4d57343e4c2516e2ff9d540bfa59285fa441d0..44f19e036fa47d87eb41dc6c35ccf72343e25444 100644 (file)
@@ -124,6 +124,9 @@ class TestHumanReadableSize(object):
         result = disk.human_readable_size(81.2*1024*1024*1024*1024)
         assert result == '81.20 TB'
 
+    def test_petabytes(self):
+        result = disk.human_readable_size(9.23*1024*1024*1024*1024*1024)
+        assert result == '9.23 PB'
 
 class TestSizeFromHumanReadable(object):
 
@@ -143,10 +146,14 @@ class TestSizeFromHumanReadable(object):
         result = disk.size_from_human_readable('2 G')
         assert result == disk.Size(gb=2)
 
-    def test_terrabytes(self):
+    def test_terabytes(self):
         result = disk.size_from_human_readable('2 T')
         assert result == disk.Size(tb=2)
 
+    def test_petabytes(self):
+        result = disk.size_from_human_readable('2 P')
+        assert result == disk.Size(pb=2)
+
     def test_case(self):
         result = disk.size_from_human_readable('2 t')
         assert result == disk.Size(tb=2)
@@ -182,10 +189,14 @@ class TestSizeParse(object):
         result = disk.Size.parse('2G')
         assert result == disk.Size(gb=2)
 
-    def test_terrabytes(self):
+    def test_terabytes(self):
         result = disk.Size.parse('2T')
         assert result == disk.Size(tb=2)
 
+    def test_petabytes(self):
+        result = disk.Size.parse('2P')
+        assert result == disk.Size(pb=2)
+
     def test_tb(self):
         result = disk.Size.parse('2Tb')
         assert result == disk.Size(tb=2)
index 3d9e19c3efe4a85ca2a790164b22c190595c07e3..88db0513817a95b6881939c426b3e1fe010fccbd 100644 (file)
@@ -402,6 +402,8 @@ class FloatKB(BaseFloatUnit):
 class FloatTB(BaseFloatUnit):
     pass
 
+class FloatPB(BaseFloatUnit):
+    pass
 
 class Size(object):
     """
@@ -456,10 +458,10 @@ class Size(object):
     @classmethod
     def parse(cls, size):
         if (len(size) > 2 and
-            size[-2].lower() in ['k', 'm', 'g', 't'] and
+            size[-2].lower() in ['k', 'm', 'g', 't', 'p'] and
             size[-1].lower() == 'b'):
             return cls(**{size[-2:].lower(): float(size[0:-2])})
-        elif size[-1].lower() in ['b', 'k', 'm', 'g', 't']:
+        elif size[-1].lower() in ['b', 'k', 'm', 'g', 't', 'p']:
             return cls(**{size[-1].lower(): float(size[0:-1])})
         else:
             return cls(b=float(size))
@@ -474,6 +476,7 @@ class Size(object):
             [('m', 'mb', 'megabytes'), self._multiplier ** 2],
             [('g', 'gb', 'gigabytes'), self._multiplier ** 3],
             [('t', 'tb', 'terabytes'), self._multiplier ** 4],
+            [('p', 'pb', 'petabytes'), self._multiplier ** 5]
         ]
         # and mappings for units-to-formatters, including bytes and aliases for
         # each
@@ -483,6 +486,7 @@ class Size(object):
             [('mb', 'megabytes'), FloatMB],
             [('gb', 'gigabytes'), FloatGB],
             [('tb', 'terabytes'), FloatTB],
+            [('pb', 'petabytes'), FloatPB],
         ]
         self._formatters = {}
         for key, value in format_aliases:
@@ -516,7 +520,7 @@ class Size(object):
         than 1024. This allows to represent size in the most readable format
         available
         """
-        for unit in ['b', 'kb', 'mb', 'gb', 'tb']:
+        for unit in ['b', 'kb', 'mb', 'gb', 'tb', 'pb']:
             if getattr(self, unit) > 1024:
                 continue
             return getattr(self, unit)
@@ -632,14 +636,15 @@ def human_readable_size(size):
     Take a size in bytes, and transform it into a human readable size with up
     to two decimals of precision.
     """
-    suffixes = ['B', 'KB', 'MB', 'GB', 'TB']
-    suffix_index = 0
-    while size > 1024:
-        suffix_index += 1
-        size = size / 1024.0
+    suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
+    for suffix in suffixes:
+        if size >= 1024:
+            size = size / 1024
+        else:
+            break
     return "{size:.2f} {suffix}".format(
         size=size,
-        suffix=suffixes[suffix_index])
+        suffix=suffix)
 
 
 def size_from_human_readable(s):
@@ -651,6 +656,8 @@ def size_from_human_readable(s):
     if s[-1].isdigit():
         return Size(b=float(s))
     n = float(s[:-1])
+    if s[-1].lower() == 'p':
+        return Size(pb=n)
     if s[-1].lower() == 't':
         return Size(tb=n)
     if s[-1].lower() == 'g':