diff --git a/probert/lvm.py b/probert/lvm.py
index 8421a39..a816793 100644
--- a/probert/lvm.py
+++ b/probert/lvm.py
@@ -19,7 +19,7 @@
import pyudev
import subprocess
-from probert.utils import read_sys_block_size
+from probert.utils import read_sys_block_size_bytes
log = logging.getLogger('probert.lvm')
@@ -122,7 +122,8 @@ def extract_lvm_partition(probe_data):
lv_id, {'fullname': lv_id,
'name': probe_data['DM_LV_NAME'],
'volgroup': probe_data['DM_VG_NAME'],
- 'size': "%sB" % read_sys_block_size(probe_data['DEVNAME'])})
+ 'size': "%sB" % read_sys_block_size_bytes(
+ probe_data['DEVNAME'])})
def extract_lvm_volgroup(vg_name, report_data):
diff --git a/probert/raid.py b/probert/raid.py
index 24f49eb..2c9c532 100644
--- a/probert/raid.py
+++ b/probert/raid.py
@@ -17,7 +17,7 @@
import pyudev
import subprocess
-from probert.utils import (read_sys_block_size,
+from probert.utils import (read_sys_block_size_bytes,
udev_get_attributes)
log = logging.getLogger('probert.raid')
@@ -115,7 +115,7 @@ def probe(context=None, report=False):
if 'MD_NAME' in device and device.get('DEVTYPE') == 'disk':
devname = device['DEVNAME']
attrs = udev_get_attributes(device)
- attrs['size'] = str(read_sys_block_size(devname))
+ attrs['size'] = str(read_sys_block_size_bytes(devname))
devices, spares = get_mdadm_array_members(devname, device)
cfg = dict(device)
cfg.update({'raidlevel': device['MD_LEVEL'],
diff --git a/probert/storage.py b/probert/storage.py
index 762077a..a27ebe1 100644
--- a/probert/storage.py
+++ b/probert/storage.py
@@ -18,7 +18,7 @@
import pyudev
import subprocess
-from probert.utils import udev_get_attributes, read_sys_block_size
+from probert.utils import udev_get_attributes, read_sys_block_size_bytes
from probert import (bcache, dmcrypt, filesystem, lvm, mount, multipath,
raid, zfs)
@@ -117,7 +117,7 @@ def _extract_partition_table(devname):
# update the size attr as it may only be the number
# of blocks rather than size in bytes.
attrs['size'] = \
- str(read_sys_block_size(device['DEVNAME']))
+ str(read_sys_block_size_bytes(device['DEVNAME']))
blockdev[device['DEVNAME']] = dict(device)
blockdev[device['DEVNAME']].update({'attrs': attrs})
# include partition table info if present
diff --git a/probert/tests/helpers.py b/probert/tests/helpers.py
index 6b74f12..e8db474 100644
--- a/probert/tests/helpers.py
+++ b/probert/tests/helpers.py
@@ -13,10 +13,38 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import contextlib
+import imp
+import importlib
+import mock
import random
import string
+def builtin_module_name():
+ options = ('builtins', '__builtin__')
+ for name in options:
+ try:
+ imp.find_module(name)
+ except ImportError:
+ continue
+ else:
+ print('importing and returning: %s' % name)
+ importlib.import_module(name)
+ return name
+
+
+@contextlib.contextmanager
+def simple_mocked_open(content=None):
+ if not content:
+ content = ''
+ m_open = mock.mock_open(read_data=content)
+ mod_name = builtin_module_name()
+ m_patch = '{}.open'.format(mod_name)
+ with mock.patch(m_patch, m_open, create=True):
+ yield m_open
+
+
def random_string(length=8):
""" return a random lowercase string with default length of 8"""
return ''.join(
diff --git a/probert/tests/test_lvm.py b/probert/tests/test_lvm.py
index 795f96a..548bd74 100644
--- a/probert/tests/test_lvm.py
+++ b/probert/tests/test_lvm.py
@@ -244,7 +244,7 @@ def test_extract_lvm_volgroup_no_size_set_to_zero_bytes(self, m_run):
'size': '0B'}),
lvm.extract_lvm_volgroup('vg0', input_data))
- @mock.patch('probert.lvm.read_sys_block_size')
+ @mock.patch('probert.lvm.read_sys_block_size_bytes')
def test_extract_lvm_partition(self, m_size, m_run):
size = 100000000
m_size.return_value = size
@@ -261,7 +261,7 @@ def test_extract_lvm_partition(self, m_size, m_run):
lvm.extract_lvm_partition(input_data))
m_size.assert_called_with('/dev/dm-2')
- @mock.patch('probert.lvm.read_sys_block_size')
+ @mock.patch('probert.lvm.read_sys_block_size_bytes')
@mock.patch('probert.lvm.activate_volgroups')
@mock.patch('probert.lvm.lvm_scan')
@mock.patch('probert.lvm.pyudev.Context.list_devices')
@@ -294,7 +294,7 @@ def test_probe(self, m_vgs, m_pyudev, m_scan, m_activate, m_size, m_run):
}
self.assertEqual(expected_result, lvm.probe())
- @mock.patch('probert.lvm.read_sys_block_size')
+ @mock.patch('probert.lvm.read_sys_block_size_bytes')
@mock.patch('probert.lvm.activate_volgroups')
@mock.patch('probert.lvm.lvm_scan')
@mock.patch('probert.lvm.pyudev.Context.list_devices')
diff --git a/probert/tests/test_utils.py b/probert/tests/test_utils.py
index 0947a8c..4ebb730 100644
--- a/probert/tests/test_utils.py
+++ b/probert/tests/test_utils.py
@@ -1,6 +1,8 @@
import testtools
+from mock import call
from probert import utils
+from probert.tests.helpers import random_string, simple_mocked_open
class ProbertTestUtils(testtools.TestCase):
@@ -35,3 +37,23 @@ def test_utils_dict_merge_dicts(self):
}
test_result = utils.dict_merge(r1, r2)
self.assertEqual(sorted(combined), sorted(test_result))
+
+ def test_utils_read_sys_block_size_bytes(self):
+ devname = random_string()
+ expected_fname = '/sys/class/block/%s/size' % devname
+ expected_bytes = 10737418240
+ content = '20971520'
+ with simple_mocked_open(content=content) as m_open:
+ result = utils.read_sys_block_size_bytes(devname)
+ self.assertEqual(expected_bytes, result)
+ self.assertEqual([call(expected_fname)], m_open.call_args_list)
+
+ def test_utils_read_sys_block_size_bytes_strips_value(self):
+ devname = random_string()
+ expected_fname = '/sys/class/block/%s/size' % devname
+ expected_bytes = 10737418240
+ content = ' 20971520 \n '
+ with simple_mocked_open(content=content) as m_open:
+ result = utils.read_sys_block_size_bytes(devname)
+ self.assertEqual(expected_bytes, result)
+ self.assertEqual([call(expected_fname)], m_open.call_args_list)
diff --git a/probert/utils.py b/probert/utils.py
index fc0b7f5..e9a2113 100644
--- a/probert/utils.py
+++ b/probert/utils.py
@@ -22,6 +22,10 @@
"bridge_hello", "bridge_maxage", "bridge_maxwait", "bridge_stp",
]
+# sysfs size attribute is always in 512-byte units
+# https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/include/linux/types.h#L125
+SECTOR_SIZE_BYTES = 512
+
# from juju-deployer utils.relation_merge
def dict_merge(onto, source):
@@ -225,21 +229,12 @@ def parse_etc_network_interfaces(ifaces, contents, path):
ifaces[iface]['auto'] = False
-def read_sys_block_size(device):
+def read_sys_block_size_bytes(device):
+ """ /sys/class/block//size and return integer value in bytes"""
device_dir = os.path.join('/sys/class/block', os.path.basename(device))
blockdev_size = os.path.join(device_dir, 'size')
with open(blockdev_size) as d:
- size = int(d.read().strip())
-
- logsize_base = device_dir
- if not os.path.exists(os.path.join(device_dir, 'queue')):
- parent_dev = os.path.basename(re.split(r'[\d+]', device)[0])
- logsize_base = os.path.join('/sys/class/block', parent_dev)
-
- logical_size = os.path.join(logsize_base, 'queue', 'logical_block_size')
- if os.path.exists(logical_size):
- with open(logical_size) as s:
- size *= int(s.read().strip())
+ size = int(d.read().strip()) * SECTOR_SIZE_BYTES
return size