← Back to team overview

curtin-dev team mailing list archive

[Merge] ~mwhudson/curtin:pare-down-dasdview-parsing into curtin:master

 

Michael Hudson-Doyle has proposed merging ~mwhudson/curtin:pare-down-dasdview-parsing into curtin:master.

Commit message:
simplify dasdview parsing code

Now that the only thing we need dasdview output for is to determine the format type of the dasd (ldl vs cdl vs unformatted) we can make a few things simpler.

Requested reviews:
  curtin developers (curtin-dev)

For more details, see:
https://code.launchpad.net/~mwhudson/curtin/+git/curtin/+merge/394207
-- 
Your team curtin developers is requested to review the proposed merge of ~mwhudson/curtin:pare-down-dasdview-parsing into curtin:master.
diff --git a/curtin/block/dasd.py b/curtin/block/dasd.py
index 7450300..8524d63 100644
--- a/curtin/block/dasd.py
+++ b/curtin/block/dasd.py
@@ -1,13 +1,12 @@
 # This file is part of curtin. See LICENSE file for copyright and license info.
 
-import collections
+import glob
 import os
+import re
 import tempfile
 from curtin import util
 from curtin.log import LOG, logged_time
 
-Dasdvalue = collections.namedtuple('Dasdvalue', ['hex', 'dec', 'txt'])
-
 
 class DasdPartition:
     def __init__(self, table, device, start, end, length, id, system):
@@ -116,196 +115,43 @@ def dasdinfo(device_id):
     return util.load_shell_content(out)
 
 
-def dasdview(devname):
-    ''' Run dasdview on devname and return dictionary of data.
-
-    dasdview --extended has 3 sections
-    general (2:6), geometry (8:12), extended (14:)
-
-    '''
+def dasd_format(devname):
+    """Return the format (ldl/cdl/not-formatted) of devname."""
     if not os.path.exists(devname):
         raise ValueError("Invalid dasd device name: '%s'" % devname)
 
     out, err = util.subp(['dasdview', '--extended', devname], capture=True)
 
-    return _parse_dasdview(out)
-
-
-def _parse_dasdview(view_output):
-    """ Parse dasdview --extended output into a dictionary
-
-    Input:
-    --- general DASD information ---------------------------------------------
-    device node            : /dev/dasdd
-    busid                  : 0.0.1518
-    type                   : ECKD
-    device type            : hex 3390       dec 13200
-
-    --- DASD geometry --------------------------------------------------------
-    number of cylinders    : hex 2721       dec 10017
-    tracks per cylinder    : hex f          dec 15
-    blocks per track       : hex c          dec 12
-    blocksize              : hex 1000       dec 4096
-
-    --- extended DASD information --------------------------------------------
-    real device number     : hex 0          dec 0
-    subchannel identifier  : hex 178        dec 376
-    CU type  (SenseID)     : hex 3990       dec 14736
-    CU model (SenseID)     : hex e9         dec 233
-    device type  (SenseID) : hex 3390       dec 13200
-    device model (SenseID) : hex c          dec 12
-    open count             : hex 1          dec 1
-    req_queue_len          : hex 0          dec 0
-    chanq_len              : hex 0          dec 0
-    status                 : hex 5          dec 5
-    label_block            : hex 2          dec 2
-    FBA_layout             : hex 0          dec 0
-    characteristics_size   : hex 40         dec 64
-    confdata_size          : hex 100        dec 256
-    format                 : hex 2          dec 2           CDL formatted
-    features               : hex 0          dec 0           default
-
-    characteristics        : 3990e933 900c5e0c  39f72032 2721000f
-                             e000e5a2 05940222  13090674 00000000
-                             00000000 00000000  32321502 dfee0001
-                             0677080f 007f4800  1f3c0000 00002721
-
-    configuration_data     : dc010100 f0f0f2f1  f0f7f9f0 f0c9c2d4
-                             f7f5f0f0 f0f0f0f0  f0c4e7d7 f7f10818
-                             d4020000 f0f0f2f1  f0f7f9f6 f1c9c2d4
-                             f7f5f0f0 f0f0f0f0  f0c4e7d7 f7f10800
-                             d0000000 f0f0f2f1  f0f7f9f6 f1c9c2d4
-                             f7f5f0f0 f0f0f0f0  f0c4e7d7 f7f00800
-                             f0000001 f0f0f2f1  f0f7f9f0 f0c9c2d4
-                             f7f5f0f0 f0f0f0f0  f0c4e7d7 f7f10800
-                             00000000 00000000  00000000 00000000
-                             00000000 00000000  00000000 00000000
-                             00000000 00000000  00000000 00000000
-                             00000000 00000000  00000000 00000000
-                             00000000 00000000  00000000 00000000
-                             00000000 00000000  00000000 00000000
-                             81000003 2d001e00  15000247 000c0016
-                             000cc018 935e41ee  00030000 0000a000
-
-    Output:
-
-    view = {
-    'extended': {
-        'chanq_len': Dasdvalue(hex='0x0', dec=0, txt=None),
-        'characteristics': ['3990e933', ...], # shortened for brevity
-        'characteristics_size': Dasdvalue(hex='0x40', dec=64, txt=None),
-        'confdata_size': Dasdvalue(hex='0x100', dec=256, txt=None),
-        'configuration_data': ['dc010100', ...], # shortened for brevity
-        'cu_model_senseid': Dasdvalue(hex='0xe9', dec=233, txt=None),
-        'cu_type__senseid': Dasdvalue(hex='0x3990', dec=14736, txt=None),
-        'device_model_senseid': Dasdvalue(hex='0xc', dec=12, txt=None),
-        'device_type__senseid': Dasdvalue(hex='0x3390', dec=13200, txt=None),
-        'fba_layout': Dasdvalue(hex='0x0', dec=0, txt=None),
-        'features': Dasdvalue(hex='0x0', dec=0, txt='default'),
-        'format': Dasdvalue(hex='0x2', dec=2, txt='cdl'),
-        'label_block': Dasdvalue(hex='0x2', dec=2, txt=None),
-        'open_count': Dasdvalue(hex='0x1', dec=1, txt=None),
-        'real_device_number': Dasdvalue(hex='0x0', dec=0, txt=None),
-        'req_queue_len': Dasdvalue(hex='0x0', dec=0, txt=None),
-        'status': Dasdvalue(hex='0x5', dec=5, txt=None),
-        'subchannel_identifier': Dasdvalue(hex='0x178', dec=376, txt=None)},
-    'general': {
-        'busid': ['0.0.1518'],
-        'device_node': ['/dev/dasdd'],
-        'device_type': Dasdvalue(hex='0x3390', dec=13200, txt=None),
-        'type': ['ECKD']},
-    'geometry': {
-        'blocks_per_track': Dasdvalue(hex='0xc', dec=12, txt=None),
-        'blocksize': Dasdvalue(hex='0x1000', dec=4096, txt=None),
-        'number_of_cylinders': Dasdvalue(hex='0x2721', dec=10017, txt=None),
-        'tracks_per_cylinder': Dasdvalue(hex='0xf', dec=15, txt=None)}
-    }
-    """
+    return _dasd_format(out)
 
-    info_key_map = {
-        'CDL formatted': 'cdl',
-        'LDL formatted': 'ldl',
-        'NOT formatted': 'not-formatted',
-    }
 
-    def _mkdasdvalue(hex_str, dec_str, comment=None):
-        v_hex = hex_str.replace('hex ', '0x')
-        v_dec = int(dec_str.replace('dec ', ''))
-        v_str = None
-        if comment is not None:
-            v_str = info_key_map.get(comment, comment)
-
-        return Dasdvalue(v_hex, v_dec, v_str)
-
-    def _map_strip(value):
-        v_type = type(value)
-        return v_type(map(lambda x: x.strip(), value))
-
-    def _parse_output(output):
-        parsed = {}
-        key = prev_key = value = None
-        for line in output:
-            if not line:
-                continue
-            if ':' in line:
-                key, value = map(lambda x: x.strip(),
-                                 line.lstrip().split(':'))
-                # normalize lvalue
-                key = key.replace('  ', '_')
-                key = key.replace(' ', '_')
-                key = key.replace('(', '').replace(')', '')
-                key = key.lower()
-                prev_key = key
-                if value and '\t' in value:
-                    value = _map_strip(value.split('\t'))
-                    # [hex X, dec Y]
-                    # [hex X, dec Y, string]
-                    value = _mkdasdvalue(*value)
-                elif value and '  ' in value:
-                    # characteristics : XXXXXXX XXXXXXX  XXXXXXXX XXXXXXX
-                    #                   YYYYYYY YYYYYYY  YYYYYYYY YYYYYYY
-                    # convert to list of strings.
-                    value = value.lstrip().split()
-                else:
-                    value = None
-            else:
-                key = prev_key
-                # no colon line, parse value from line
-                #                   YYYYYYY YYYYYYY  YYYYYYYY YYYYYYY
-                value = line.lstrip().split()
-
-            # extend lists for existing keys
-            if key in parsed and type(value) == list:
-                parsed[key].extend(value)
-            else:
-                parsed.update({key: value})
-
-        return parsed
-
-    if not view_output or not isinstance(view_output, util.string_types):
-        raise ValueError(
-            'Invalid value for input to parse: ' + str(view_output))
+DASD_FORMAT = r"^format\s+:.+\s+(?P<value>\w+\s\w+)$"
+
+
+def find_val(regex, content):
+    m = re.search(regex, content, re.MULTILINE)
+    if m is not None:
+        return m.group("value")
 
-    # XXX: dasdview --extended has 52 lines for dasd devices
-    if len(view_output.splitlines()) < 52:
-        raise ValueError(
-            'dasdview output has fewer than 52 lines, cannot parse')
 
-    lines = view_output.splitlines()
-    gen_start, gen_end = (2, 6)
-    geo_start, geo_end = (8, 12)
-    ext_start, ext_end = (14, len(lines))
+def _dasd_format(dasdview_output):
+    """ Read and return specified device "disk_layout" value.
 
-    general_output = lines[gen_start:gen_end]
-    geometry_output = lines[geo_start:geo_end]
-    extended_output = lines[ext_start:ext_end]
+    :returns: string: One of ['cdl', 'ldl', 'not-formatted'].
+    :raises: ValueError if dasdview result missing 'format' section.
 
-    view = {
-        'general': _parse_output(general_output),
-        'geometry': _parse_output(geometry_output),
-        'extended': _parse_output(extended_output),
+    """
+    if not dasdview_output:
+        return
+
+    mapping = {
+       'cdl formatted': 'cdl',
+       'ldl formatted': 'ldl',
+       'not formatted': 'not-formatted',
     }
-    return view
+    diskfmt = find_val(DASD_FORMAT, dasdview_output)
+    if diskfmt is not None:
+        return mapping.get(diskfmt.lower())
 
 
 def _valid_device_id(device_id):
@@ -371,38 +217,9 @@ class CcwDevice(object):
 
 class DasdDevice(CcwDevice):
 
-    def __init__(self, device_id):
-        super(DasdDevice, self).__init__(device_id)
-        self._kname = None
-
-    @property
-    def kname(self):
-        if not self._kname:
-            self._kname = self._get_kname()
-        return self._kname
-
-    def _get_kname(self):
-        """ Return the kernel name of the dasd device. """
-        if not self.is_online():
-            raise RuntimeError('Cannot determine dasd kname for offline '
-                               'device: %s' % self.device_id)
-
-        blockdir = self.ccw_device_attr_path('block')
-        if not os.path.isdir(blockdir):
-            raise RuntimeError('Unexpectedly not a directory: %s' % blockdir)
-
-        try:
-            knames = os.listdir(blockdir)
-            [dasd_kname] = knames
-        except ValueError:
-            raise RuntimeError('Unexpected os.listdir result at sysfs path '
-                               '%s: "%s"' % (blockdir, knames))
-
-        return dasd_kname
-
     @property
     def devname(self):
-        return '/dev/%s' % self.kname
+        return '/dev/disk/by-path/ccw-%s' % self.device_id
 
     def partition(self, partnumber, partsize, strict=True):
         """ Add a partition to this DasdDevice specifying partnumber and size.
@@ -461,42 +278,31 @@ class DasdDevice(CcwDevice):
         """ Returns a boolean indicating if the specified device_id is not yet
             formatted.
 
-        :param device_id: string of device ccw bus_id.
         :returns: boolean: True if the device is not formatted.
         """
         return self.ccw_device_attr('status') == "unformatted"
 
-    def is_online(self):
-        """ Returns a boolean indicating if specified device is online.
-
-        :param device_id: string of device ccw bus_id.
-        :returns: boolean: True if device is online.
-        """
-        return self.ccw_device_attr('online') == "1"
-
     def blocksize(self):
         """ Read and return device_id's 'blocksize' value.
 
         :param: device_id: string of device ccw bus_id.
         :returns: string: the device's current blocksize.
         """
-        blkattr = 'block/%s/queue/hw_sector_size' % self.kname
-        return self.ccw_device_attr(blkattr)
+        blkattr = 'block/*/queue/hw_sector_size'
+        [path] = glob.glob(self.ccw_device_attr_path(blkattr))
+        return util.load_file(path)
 
     def disk_layout(self):
         """ Read and return specified device "disk_layout" value.
 
         :returns: string: One of ['cdl', 'ldl', 'not-formatted'].
         :raises: ValueError if dasdview result missing 'format' section.
-
         """
-        view = dasdview(self.devname)
-        disk_format = view.get('extended', {}).get('format')
-        if not disk_format:
+        format = dasd_format(self.devname)
+        if not format:
             raise ValueError(
-                'dasdview on %s missing "format" section' % self.devname)
-
-        return disk_format.txt
+                'could not determine format of %s' % self.devname)
+        return format
 
     def label(self):
         """Read and return specified device label (VOLSER) value.
@@ -546,7 +352,7 @@ class DasdDevice(CcwDevice):
 
     @logged_time("DASD.FORMAT")
     def format(self, blksize=4096, layout='cdl', force=False, set_label=None,
-               keep_label=False, no_label=False, mode='quick', strict=True):
+               keep_label=False, no_label=False, mode='quick'):
         """ Format DasdDevice with supplied parameters.
 
         :param blksize: integer value to configure disk block size in bytes.
@@ -572,7 +378,7 @@ class DasdDevice(CcwDevice):
         :param strict: boolean which enforces that dasd device exists before
             issuing format command, defaults to True.
 
-        :raises: RuntimeError if strict==True and devname does not exist.
+        :raises: RuntimeError if devname does not exist.
         :raises: ValueError on invalid blocksize, disk_layout and mode.
         :raises: ProcessExecutionError on errors running 'dasdfmt' command.
 
@@ -580,7 +386,7 @@ class DasdDevice(CcwDevice):
           dasdformat -y --blocksize=4096 --disk_layout=cdl \
                      --mode=quick /dev/dasda
         """
-        if strict and not os.path.exists(self.devname):
+        if not os.path.exists(self.devname):
             raise RuntimeError("devname '%s' does not exist" % self.devname)
 
         if no_label:
diff --git a/tests/unittests/test_block_dasd.py b/tests/unittests/test_block_dasd.py
index dfd62d3..fffa4a1 100644
--- a/tests/unittests/test_block_dasd.py
+++ b/tests/unittests/test_block_dasd.py
@@ -85,80 +85,18 @@ class TestDasdValidDeviceId(CiTestCase):
             dasd.DasdDevice(invalid_dev)
 
 
-class TestDasdDeviceIdToKname(CiTestCase):
-
-    def setUp(self):
-        super(TestDasdDeviceIdToKname, self).setUp()
-        self.add_patch('curtin.block.dasd.os.path.isdir', 'm_isdir')
-        self.add_patch('curtin.block.dasd.os.listdir', 'm_listdir')
-        self.add_patch('curtin.block.dasd.DasdDevice.is_online', 'm_online')
-
-        self.dasd = dasd.DasdDevice(random_device_id())
-        self.m_online.return_value = True
-        self.m_isdir.return_value = True
-        self.m_listdir.return_value = [self.random_string()]
-
-    def test_device_id_to_kname_returns_kname(self):
-        """returns a dasd kname if device_id is valid and online """
-        result = self.dasd.kname
-        self.assertIsNotNone(result)
-        self.assertEqual(result, self.m_listdir.return_value[0])
-
-    def test_devid_to_kname_raises_runtimeerror_no_online(self):
-        """device_id_to_kname raises RuntimeError on offline devices."""
-        self.m_online.return_value = False
-        result = None
-        with self.assertRaises(RuntimeError):
-            result = self.dasd.kname
-        self.assertEqual(result, None)
-        self.assertEqual(1, self.m_online.call_count)
-        self.assertEqual(0, self.m_isdir.call_count)
-        self.assertEqual(0, self.m_listdir.call_count)
-
-    def test_devid_to_kname_raises_runtimeerror_no_blockpath(self):
-        """device_id_to_kname raises RuntimeError on invalid sysfs path."""
-        self.m_isdir.return_value = False
-        result = None
-        with self.assertRaises(RuntimeError):
-            result = self.dasd.kname
-        self.assertEqual(result, None)
-        self.assertEqual(1, self.m_online.call_count)
-        self.assertEqual(1, self.m_isdir.call_count)
-        self.m_isdir.assert_called_with(
-            '/sys/bus/ccw/devices/%s/block' % self.dasd.device_id)
-        self.assertEqual(0, self.m_listdir.call_count)
-
-    def test_devid_to_kname_raises_runtimeerror_empty_blockdir(self):
-        """device_id_to_kname raises RuntimeError on empty blockdir."""
-        self.m_listdir.return_value = []
-        result = None
-        with self.assertRaises(RuntimeError):
-            result = self.dasd.kname
-        self.assertEqual(result, None)
-        self.assertEqual(1, self.m_online.call_count)
-        self.assertEqual(1, self.m_isdir.call_count)
-        self.m_isdir.assert_called_with(
-            '/sys/bus/ccw/devices/%s/block' % self.dasd.device_id)
-        self.m_listdir.assert_called_with(
-            '/sys/bus/ccw/devices/%s/block' % self.dasd.device_id)
-        self.assertEqual(1, self.m_listdir.call_count)
-
-
 class TestDasdCcwDeviceAttr(CiTestCase):
 
     def setUp(self):
         super(TestDasdCcwDeviceAttr, self).setUp()
         self.add_patch('curtin.block.dasd.os.path.isfile', 'm_isfile')
         self.add_patch('curtin.block.dasd.util.load_file', 'm_loadfile')
-        dpath = 'curtin.block.dasd.DasdDevice'
-        self.add_patch(dpath + '.kname', 'm_kname')
+        self.add_patch('curtin.block.dasd.glob.glob', 'm_glob')
 
         # defaults
         self.m_isfile.return_value = True
         self.m_loadfile.return_value = self.random_string()
         self.dasd = dasd.DasdDevice(random_device_id())
-        self.kname = self.random_string()
-        self.m_kname.return_value = self.kname
 
     def _test_ccw_attr(self, my_attr=None, attr_val_in=None, attr_val=None):
         if not my_attr:
@@ -200,60 +138,37 @@ class TestDasdCcwDeviceAttr(CiTestCase):
         self.m_loadfile.return_value = self.random_string()
         self.assertFalse(self.dasd.is_not_formatted())
 
-    def test_is_online_returns_false_if_not_online(self):
-        self.m_loadfile.return_value = self.random_string()
-        self.assertFalse(self.dasd.is_online())
-
     def test_blocksize(self):
         blocksize_val = '%d' % random.choice([512, 1024, 2048, 4096])
+        path = self.random_string()
+        self.m_glob.return_value = [path]
         self.m_loadfile.return_value = blocksize_val
         self.assertEqual(blocksize_val, self.dasd.blocksize())
+        self.m_loadfile.assert_called_once_with(path)
 
 
 class TestDiskLayout(CiTestCase):
 
-    layouts = {
-        'not-formatted': dasd.Dasdvalue(0x0, 0, 'not-formatted'),
-        'ldl': dasd.Dasdvalue(0x1, 1, 'ldl'),
-        'cdl': dasd.Dasdvalue(0x2, 2, 'cdl'),
-    }
-
     def setUp(self):
         super(TestDiskLayout, self).setUp()
-        self.add_patch('curtin.block.dasd.os.path.exists', 'm_exists')
-        self.add_patch('curtin.block.dasd.dasdview', 'm_dasdview')
+        self.add_patch('curtin.block.dasd.dasd_format', 'm_dasd_format')
         dpath = 'curtin.block.dasd.DasdDevice'
         self.add_patch(dpath + '.devname', 'm_devname')
 
-        # defaults
-        self.m_exists.return_value = True
-        self.m_dasdview.return_value = self._mkview()
         self.dasd = dasd.DasdDevice(random_device_id())
         self.devname = self.random_string()
         self.m_devname.return_value = self.devname
 
-    @classmethod
-    def _mkview(cls, layout=None):
-        if not layout:
-            layout = random.choice(list(cls.layouts.values()))
-        return {'extended': {'format': layout}}
-
-    # XXX: Parameterize me
-    def test_disk_layout_returns_dasd_extended_format_value(self):
+    def test_disk_layout_returns_dasd_format_result(self):
         """disk_layout returns dasd disk_layout format as string"""
-        for my_layout in self.layouts.values():
-            self.m_dasdview.return_value = self._mkview(layout=my_layout)
-            self.assertEqual(my_layout.txt, self.dasd.disk_layout())
+        expected = self.m_dasd_format.return_value = self.random_string()
+        self.assertEqual(expected, self.dasd.disk_layout())
 
-    # XXX: Parameterize me
-    def test_disk_layout_raises_valueerror_on_missing_format_section(self):
+    def test_disk_layout_raises_valueerror_on_missing_format(self):
         """disk_layout raises ValueError if view missing 'format' section."""
-        for my_layout in self.layouts.values():
-            view = self._mkview(layout=my_layout)
-            view['extended']['format'] = None
-            self.m_dasdview.return_value = view
-            with self.assertRaises(ValueError):
-                self.dasd.disk_layout()
+        self.m_dasd_format.return_value = None
+        with self.assertRaises(ValueError):
+            self.dasd.disk_layout()
 
 
 class TestLabel(CiTestCase):
@@ -287,8 +202,6 @@ class TestLabel(CiTestCase):
 
 class TestNeedsFormatting(CiTestCase):
 
-    blocksizes = [512, 1024, 2048, 4096]
-
     def setUp(self):
         super(TestNeedsFormatting, self).setUp()
         dpath = 'curtin.block.dasd.DasdDevice'
@@ -298,8 +211,10 @@ class TestNeedsFormatting(CiTestCase):
         self.add_patch(dpath + '.label', 'm_label')
 
         self.m_not_fmt.return_value = False
-        self.m_blocksize.return_value = 4096
-        self.m_disk_layout.return_value = TestDiskLayout.layouts['cdl'].txt
+        self.blocksize = 4096
+        self.m_blocksize.return_value = self.blocksize
+        self.disk_layout = self.random_string()
+        self.m_disk_layout.return_value = self.disk_layout
         self.label = self.random_string()
         self.m_label.return_value = self.label
 
@@ -308,26 +223,34 @@ class TestNeedsFormatting(CiTestCase):
     def test_needs_formatting_label_mismatch(self):
         my_label = self.random_string()
         self.assertNotEqual(self.label, my_label)
-        self.assertTrue(self.dasd.needs_formatting(4096, 'cdl', my_label))
+        self.assertTrue(
+            self.dasd.needs_formatting(
+                self.blocksize, self.disk_layout, my_label))
 
     def test_needs_formatting_layout_mismatch(self):
-        my_layout = TestDiskLayout.layouts['ldl'].txt
+        my_layout = self.random_string()
+        self.assertNotEqual(self.disk_layout, my_layout)
         self.assertTrue(
-            self.dasd.needs_formatting(4096, my_layout, self.label))
+            self.dasd.needs_formatting(
+                self.blocksize, my_layout, self.label))
 
     def test_needs_formatting_blocksize_mismatch(self):
-        my_blocksize = random.choice(self.blocksizes[0:3])
+        my_blocksize = random.randrange(self.blocksize)
+        self.assertNotEqual(self.blocksize, my_blocksize)
         self.assertTrue(
-            self.dasd.needs_formatting(my_blocksize, 'cdl', self.label))
+            self.dasd.needs_formatting(
+                my_blocksize, self.disk_layout, self.label))
 
     def test_needs_formatting_unformatted_disk(self):
         self.m_not_fmt.return_value = True
         self.assertTrue(
-            self.dasd.needs_formatting(4096, 'cdl', self.label))
+            self.dasd.needs_formatting(
+                self.blocksize, self.disk_layout, self.label))
 
     def test_needs_formatting_ignores_label_mismatch(self):
         self.assertFalse(
-            self.dasd.needs_formatting(4096, 'cdl', None))
+            self.dasd.needs_formatting(
+                self.blocksize, self.disk_layout, None))
 
 
 class TestFormat(CiTestCase):
@@ -346,10 +269,6 @@ class TestFormat(CiTestCase):
         self.devname = self.random_string()
         self.m_devname.return_value = self.devname
 
-    def test_format_devname_ignores_path_missing_strict_false(self):
-        self.m_exists.return_value = False
-        self.dasd.format(strict=False)
-
     def test_format_defaults_match_docstring(self):
         self.dasd.format()
         self.m_subp.assert_called_with(
@@ -454,9 +373,39 @@ class TestDasdInfo(CiTestCase):
             dasd.dasdinfo(device_id)
 
 
-class TestDasdView(CiTestCase):
+class TestDasdFormat(CiTestCase):
+
+    def setUp(self):
+        super(TestDasdFormat, self).setUp()
+        self.add_patch('curtin.block.dasd.util.subp', 'm_subp')
+        self.add_patch('curtin.block.dasd.os.path.exists', 'm_exists')
+        self.add_patch('curtin.block.dasd._dasd_format', 'm_dasd_format')
+
+        # defaults
+        self.m_exists.return_value = True
+        self.m_subp.return_value = ('', '')
+
+    def test_dasd_format_raise_error_on_invalid_device(self):
+        """dasdview raises error on invalid device path."""
+        devname = self.random_string()
+        self.m_exists.return_value = False
+        with self.assertRaises(ValueError):
+            dasd.dasd_format(devname)
+
+    def test_dasd_foramt_calls__dasd_format(self):
+        """dasdview calls parser on output from dasdview command."""
+        devname = self.random_string()
+        view = self.random_string()
+        self.m_subp.return_value = (view, self.random_string())
+        dasd.dasd_format(devname)
+        self.m_subp.assert_called_with(
+            ['dasdview', '--extended', devname], capture=True)
+        self.m_dasd_format.assert_called_with(view)
+
+
+class Test_DasdFormat(CiTestCase):
 
-    view = textwrap.dedent("""\
+    view_output_template = textwrap.dedent("""\
 
     --- general DASD information ----------------------------------------------
     device node            : /dev/dasdd
@@ -485,7 +434,7 @@ class TestDasdView(CiTestCase):
     FBA_layout             : hex 0  	dec 0
     characteristics_size   : hex 40  	dec 64
     confdata_size          : hex 100  	dec 256
-    format                 : hex 2  	dec 2      	CDL formatted
+    format                 : hex 2  	dec 2      	{format}
     features               : hex 0  	dec 0      	default
 
     characteristics        : 3990e933 900c5e0c  39f72032 2721000f
@@ -510,59 +459,15 @@ class TestDasdView(CiTestCase):
                              81000003 2d001e00  15000247 000c0016
                              000cc018 935e41ee  00030000 0000a000""")
 
-    view_nondasd = textwrap.dedent("""\
-    Error: dasdview: Could not retrieve disk information!
-
-    """)
-
-    def setUp(self):
-        super(TestDasdView, self).setUp()
-        self.add_patch('curtin.block.dasd.util.subp', 'm_subp')
-        self.add_patch('curtin.block.dasd.os.path.exists', 'm_exists')
-        self.add_patch('curtin.block.dasd._parse_dasdview', 'm_parseview')
-
-        # defaults
-        self.m_exists.return_value = True
-        self.m_subp.return_value = ('', '')
-
-    def test_dasdview_raise_error_on_invalid_device(self):
-        """dasdview raises error on invalid device path."""
-        devname = self.random_string()
-        self.m_exists.return_value = False
-        with self.assertRaises(ValueError):
-            dasd.dasdview(devname)
-
-    def test_dasdview_calls_parse_dasdview(self):
-        """dasdview calls parser on output from dasdview command."""
-        devname = self.random_string()
-        self.m_subp.return_value = (self.view, self.random_string())
-        dasd.dasdview(devname)
-        self.m_subp.assert_called_with(
-            ['dasdview', '--extended', devname], capture=True)
-        self.m_parseview.assert_called_with(self.view)
-
-
-class TestParseDasdView(CiTestCase):
-
-    def test_parse_dasdview_no_input(self):
-        """_parse_dasdview raises ValueError on invalid status input."""
-        for view_output in [None, 123, {}, (), []]:
-            with self.assertRaises(ValueError):
-                dasd._parse_dasdview(view_output)
-
-    def test_parse_dasdview_invalid_strings_short(self):
-        """_parse_dasdview raises ValueError on invalid long input."""
-        with self.assertRaises(ValueError):
-            dasd._parse_dasdview("\n".join([self.random_string()] * 20))
-
-    def test_parse_dasdview_returns_dictionary(self):
+    def test__dasd_format_returns_format(self):
         """_parse_dasdview returns dict w/ required keys parsing valid view."""
-        result = dasd._parse_dasdview(TestDasdView.view)
-        self.assertEqual(dict, type(result))
-        self.assertNotEqual({}, result)
-        self.assertEqual(3, len(result.keys()))
-        for key in result.keys():
-            self.assertEqual(dict, type(result[key]))
-            self.assertNotEqual(0, len(list(result[key].keys())))
+        for (format, expected) in [
+                ('CDL formatted', 'cdl'),
+                ('LDL formatted', 'ldl'),
+                ('not formatted', 'not-formatted'),
+                ]:
+            result = dasd._dasd_format(
+                self.view_output_template.format(format=format))
+            self.assertEqual(result, expected)
 
 # vi: ts=4 expandtab syntax=python

Follow ups