Skip to content

Commit

Permalink
Use geom to perform a safe and fast disks grain on FreeBSD
Browse files Browse the repository at this point in the history
  • Loading branch information
kev009 committed May 24, 2016
1 parent 9e6ae66 commit 07d66cc
Showing 1 changed file with 65 additions and 73 deletions.
138 changes: 65 additions & 73 deletions salt/grains/disks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,91 +29,83 @@ def disks():
Return list of disk devices
'''
if salt.utils.is_freebsd():
return _freebsd_disks()
return _freebsd_geom()
elif salt.utils.is_linux():
return _linux_disks()
else:
log.trace('Disk grain does not support OS')


def _clean_keys(key):
key = key.replace(' ', '_')
key = key.replace('(', '')
key = key.replace(')', '')
return key


class _camconsts(object):
PROTOCOL = 'protocol'
DEVICE_MODEL = 'device model'
FIRMWARE_REVISION = 'firmware revision'
SERIAL_NUMBER = 'serial number'
WWN = 'WWN'
SECTOR_SIZE = 'sector size'
MEDIA_RPM = 'media RPM'

_identify_attribs = [_camconsts.__dict__[key] for key in
_camconsts.__dict__ if not key.startswith('__')]
class _geomconsts(object):
GEOMNAME = 'Geom name'
MEDIASIZE = 'Mediasize'
SECTORSIZE = 'Sectorsize'
STRIPESIZE = 'Stripesize'
STRIPEOFFSET = 'Stripeoffset'
DESCR = 'descr' # model
LUNID = 'lunid'
LUNNAME = 'lunname'
IDENT = 'ident' # serial
ROTATIONRATE = 'rotationrate' # RPM or 0 for non-rotating

# Preserve the API where possible with Salt < 2016.3
_aliases = {
DESCR: 'device_model',
IDENT: 'serial_number',
ROTATIONRATE: 'media_RPM',
LUNID: 'WWN',
}

_datatypes = {
MEDIASIZE: ('re_int', r'(\d+)'),
SECTORSIZE: 'int',
STRIPESIZE: 'int',
STRIPEOFFSET: 'int',
ROTATIONRATE: 'int',
}


def _datavalue(datatype, data):
if datatype == 'int':
return int(data)
elif datatype and datatype[0] == 're_int':
return int(re.search(datatype[1], data).group(1))
else:
return data


@decorators.memoize
def _freebsd_vbox():
# Don't tickle VirtualBox storage emulation bugs
camcontrol = salt.utils.which('camcontrol')
devlist = __salt__['cmd.run']('{0} devlist'.format(camcontrol))
if 'VBOX' in devlist:
return True
return False
_geom_attribs = [_geomconsts.__dict__[key] for key in
_geomconsts.__dict__ if not key.startswith('_')]


def _freebsd_disks():
def _freebsd_geom():
geom = salt.utils.which('geom')
ret = {'disks': {}, 'SSDs': []}
sysctl = salt.utils.which('sysctl')
devices = __salt__['cmd.run']('{0} -n kern.disks'.format(sysctl))
SSD_TOKEN = 'non-rotating'

for device in devices.split(' '):
if device.startswith('cd'):
log.debug('Disk grain skipping cd')
elif _freebsd_vbox():
log.debug('Disk grain skipping CAM identify/inquirty on VBOX')
ret['disks'][device] = {}
else:
cam = _freebsd_camcontrol(device)
ret['disks'][device] = cam
if cam.get(_clean_keys(_camconsts.MEDIA_RPM)) == SSD_TOKEN:
ret['SSDs'].append(device)

return ret


def _freebsd_camcontrol(device):
camcontrol = salt.utils.which('camcontrol')
ret = {}

def parse_identify_attribs(line):
for attrib in _identify_attribs:
search = re.search(r'^{0}\s+(.*)'.format(attrib), line)
if search:
ret[_clean_keys(attrib)] = search.group(1)

identify = __salt__['cmd.run']('{0} identify {1}'.format(camcontrol,
device))
for line in identify.splitlines():
parse_identify_attribs(line)

def parse_inquiry(inquiry):
if not ret.get(_clean_keys(_camconsts.DEVICE_MODEL)):
model = re.search(r'\s<(.+?)>', inquiry)
if model:
ret[_clean_keys(_camconsts.DEVICE_MODEL)] = model.group(1)
if not ret.get(_clean_keys(_camconsts.SERIAL_NUMBER)):
sn = re.search(r'\sSerial Number\s+(\w+)\s', inquiry)
if sn:
ret[_clean_keys(_camconsts.SERIAL_NUMBER)] = sn.group(1)

inquiry = __salt__['cmd.run']('{0} inquiry {1}'.format(camcontrol, device))
parse_inquiry(inquiry)
devices = __salt__['cmd.run']('{0} disk list'.format(geom))
devices = devices.split('\n\n')

def parse_geom_attribs(device):
tmp = {}
for line in device.split('\n'):
for attrib in _geom_attribs:
search = re.search(r'{0}:\s(.*)'.format(attrib), line)
if search:
value = _datavalue(_geomconsts._datatypes.get(attrib),
search.group(1))
tmp[attrib] = value
if attrib in _geomconsts._aliases:
tmp[_geomconsts._aliases[attrib]] = value

name = tmp.pop(_geomconsts.GEOMNAME)

ret['disks'][name] = tmp
if tmp[_geomconsts.ROTATIONRATE] == 0:
log.trace('Device {0} reports itself as an SSD'.format(device))
ret['SSDs'].append(name)

for device in devices:
parse_geom_attribs(device)

return ret

Expand Down

0 comments on commit 07d66cc

Please sign in to comment.