Skip to content

Commit

Permalink
Merge pull request #78 from raharper/feature/probe-dasd
Browse files Browse the repository at this point in the history
storage: add dasd prober
  • Loading branch information
raharper authored Feb 25, 2020
2 parents 4c3ab9b + c85be86 commit 38c4107
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 1 deletion.
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Depends: probert-common (= ${source:Version}),
lvm2,
mdadm,
multipath-tools,
s390-tools [s390x],
zfsutils-linux,
${misc:Depends},
${python3:Depends},
Expand Down
143 changes: 143 additions & 0 deletions probert/dasd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Copyright 2020 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
import os
import platform
import pyudev
import re
import subprocess

log = logging.getLogger('probert.dasd')

DASD_FORMAT = r"^format\s+:.+\s+(?P<format>\w+\s\w+)$"
DASD_BLKSIZE = r"^blocksize\s+:\shex\s\w+\s+dec\s(?P<blksize>\d+)$"


def _search(regex, content, groupkey):
m = re.search(regex, content, re.MULTILINE)
if m:
return m.group(groupkey)


def blocksize(dasdview_output):
""" Read and return device_id's 'blocksize' value.
:param: device_id: string of device ccw bus_id.
:returns: int: the device's current blocksize.
"""
if not dasdview_output:
return

blksize = _search(DASD_BLKSIZE, dasdview_output, 'blksize')
if blksize:
return int(blksize)


def disk_format(dasdview_output):
""" Read and return specified device "disk_layout" value.
:returns: string: One of ['cdl', 'ldl', 'not-formatted'].
:raises: ValueError if dasdview result missing 'format' section.
"""
if not dasdview_output:
return

mapping = {
'cdl formatted': 'cdl',
'ldl formatted': 'ldl',
'not formatted': 'not-formatted',
}
diskfmt = _search(DASD_FORMAT, dasdview_output, 'format')
if diskfmt:
return mapping.get(diskfmt.lower())


def dasdview(devname):
''' Run dasdview on devname and return the output.
dasdview --extended has 3 sections
general (2:6), geometry (8:12), extended (14:)
'''
if not os.path.exists(devname):
raise ValueError("Invalid dasd device name: '%s'" % devname)

cmd = ['dasdview', '--extended', devname]
try:
result = subprocess.run(cmd, stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL)
except (subprocess.CalledProcessError, FileNotFoundError):
log.error('Failed to run cmd: %s', cmd)
return None

return result.stdout.decode('utf-8')


def get_dasd_info(device):
""" from a udev blockdev device entry, return all required dasd info
"""
name = device.get('DEVNAME')
device_id = device.get('ID_PATH', '').replace('ccw-', '')
dasdview_output = dasdview(name)
diskfmt = disk_format(dasdview_output)
blksize = blocksize(dasdview_output)
if not all([name, device_id, diskfmt, blksize]):
vals = ("name=%s device_id=%s format=%s blksize=%s" % (
name, device_id, diskfmt, blksize))
log.debug('Failed to probe some DASD values: %s', vals)
return None

return {'name': name, 'device_id': device_id,
'disk_layout': diskfmt, 'blocksize': blksize}


def probe(context=None):
"""Examine all dasd devices present and extract configuration attributes
This data is useful for determining if the dasd device has been
formatted, if so what the block size, the partition layout used
and the s390x device_id used to uniquely identify the device.
"""
log.debug('Probing DASD devies')
machine = platform.machine()
if machine != "s390x":
log.debug('DASD devices only present on s390x, arch=%s', machine)
return {}

dasds = {}
if not context:
context = pyudev.Context()

for device in context.list_devices(subsystem='block'):
# dasd devices have MAJOR 94
if device['MAJOR'] != "94":
continue
# ignore dasd partitions
if 'PARTN' in device:
continue

try:
dasd_info = get_dasd_info(device)
except ValueError as e:
log.error('Error probing dasd device %s: %s', device['DEVNAME'], e)
dasd_info = None

if dasd_info:
dasds[device['DEVNAME']] = dasd_info

return dasds
3 changes: 2 additions & 1 deletion probert/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import subprocess

from probert.utils import udev_get_attributes, read_sys_block_size_bytes
from probert import (bcache, dmcrypt, filesystem, lvm, mount, multipath,
from probert import (bcache, dasd, dmcrypt, filesystem, lvm, mount, multipath,
raid, zfs)

log = logging.getLogger('probert.storage')
Expand Down Expand Up @@ -145,6 +145,7 @@ class Storage():
probe_map = {
'bcache': bcache.probe,
'blockdev': blockdev_probe,
'dasd': dasd.probe,
'dmcrypt': dmcrypt.probe,
'filesystem': filesystem.probe,
'lvm': lvm.probe,
Expand Down
52 changes: 52 additions & 0 deletions probert/tests/data/dasdd.view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

--- general DASD information --------------------------------------------------
device node : /dev/dasdd
busid : 0.0.1544
type : ECKD
device type : hex 3390 dec 13200

--- DASD geometry -------------------------------------------------------------
number of cylinders : hex 7563 dec 30051
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 1a4 dec 420
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 2 dec 2
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 7563000f
e000e5a2 05940222 13090674 00000000
00000000 00000000 32321502 dfee0001
0677080f 007f4800 1f3c0000 00007563

configuration_data : dc010100 f0f0f2f1 f0f7f9f0 f0c9c2d4
f7f5f0f0 f0f0f0f0 f0c4e7d7 f7f10844
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
000cc044 0a0f61ca 00030000 0000a000
52 changes: 52 additions & 0 deletions probert/tests/data/dasde.view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

--- general DASD information --------------------------------------------------
device node : /dev/dasde
busid : 0.0.2520
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 0 dec 0
blocksize : hex 200 dec 512

--- extended DASD information -------------------------------------------------
real device number : hex 0 dec 0
subchannel identifier : hex 5e0 dec 1504
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 3 dec 3
label_block : hex 2 dec 2
FBA_layout : hex 1 dec 1
characteristics_size : hex 40 dec 64
confdata_size : hex 100 dec 256
format : hex 0 dec 0 NOT 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 f7f10920
d4020000 f0f0f2f1 f0f7f9f6 f1c9c2d4
f7f5f0f0 f0f0f0f0 f0c4e7d7 f7f10900
d0000000 f0f0f2f1 f0f7f9f6 f1c9c2d4
f7f5f0f0 f0f0f0f0 f0c4e7d7 f7f00900
f0000001 f0f0f2f1 f0f7f9f0 f0c9c2d4
f7f5f0f0 f0f0f0f0 f0c4e7d7 f7f10900
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 25000246 000c0016
000cc020 84228958 00030000 0000a000
Loading

0 comments on commit 38c4107

Please sign in to comment.