Add support for LVM and RAID to mount-all-volumes

* Renamed get_mounted_data to get_mounted_volumes
* Report data is now a dict for better clarity
* Widened report hoping that LVM names will fit (they probably wont)
* This fixes #38
This commit is contained in:
2Shirt 2018-05-21 20:25:12 -06:00
parent e6b7cc602b
commit 24df753a40
2 changed files with 70 additions and 57 deletions

View file

@ -170,93 +170,106 @@ def is_valid_wim_file(item):
print_log('WARNING: Image "{}" damaged.'.format(item.name)) print_log('WARNING: Image "{}" damaged.'.format(item.name))
return valid return valid
def get_mounted_data(): def get_mounted_volumes():
"""Get mounted volumes, returns dict.""" """Get mounted volumes, returns dict."""
cmd = [ cmd = [
'findmnt', '-J', '-b', '-i', 'findmnt', '-J', '-b', '-i',
't', ( '-t', (
'autofs,binfmt_misc,cgroup,cgroup2,configfs,debugfs,devpts,devtmpfs,' 'autofs,binfmt_misc,bpf,cgroup,cgroup2,configfs,debugfs,devpts,devtmpfs,'
'hugetlbfs,mqueue,proc,pstore,securityfs,sysfs,tmpfs' 'hugetlbfs,mqueue,proc,pstore,securityfs,sysfs,tmpfs'
), ),
'-o', 'SOURCE,TARGET,FSTYPE,LABEL,SIZE,AVAIL,USED'] '-o', 'SOURCE,TARGET,FSTYPE,LABEL,SIZE,AVAIL,USED']
result = run_program(cmd) result = run_program(cmd)
json_data = json.loads(result.stdout.decode()) json_data = json.loads(result.stdout.decode())
mounted_data = [] mounted_volumes = []
for item in json_data.get('filesystems', []): for item in json_data.get('filesystems', []):
mounted_data.append(item) mounted_volumes.append(item)
mounted_data.extend(item.get('children', [])) mounted_volumes.extend(item.get('children', []))
return {item['source']: item for item in mounted_data} return {item['source']: item for item in mounted_volumes}
def mount_all_volumes(): def mount_all_volumes():
"""Mount all attached devices with recognized filesystems.""" """Mount all detected filesystems."""
report = [] report = {}
# Get list of block devices # Get list of block devices
cmd = ['lsblk', '-J', '-o', 'NAME,FSTYPE,LABEL,UUID,PARTTYPE,TYPE,SIZE'] cmd = [
'lsblk', '-J', '-p',
'-o', 'NAME,FSTYPE,LABEL,UUID,PARTTYPE,TYPE,SIZE']
result = run_program(cmd) result = run_program(cmd)
json_data = json.loads(result.stdout.decode()) json_data = json.loads(result.stdout.decode())
devs = json_data.get('blockdevices', []) devs = json_data.get('blockdevices', [])
# Get list of mounted devices # Get list of volumes
mounted_data = get_mounted_data() volumes = {}
mounted_list = [m['source'] for m in mounted_data.values()]
# Loop over devices
for dev in devs: for dev in devs:
dev_path = '/dev/{}'.format(dev['name'])
if re.search(r'^(loop|sr)', dev['name'], re.IGNORECASE):
# Skip loopback devices and optical media
report.append([dev_path, 'Skipped'])
continue
for child in dev.get('children', []): for child in dev.get('children', []):
child_path = '/dev/{}'.format(child['name']) volumes.update({child['name']: child})
if child_path in mounted_list: for grandchild in child.get('children', []):
report.append([child_path, 'Already Mounted']) volumes.update({grandchild['name']: grandchild})
else:
try: # Get list of mounted volumes
run_program(['udevil', 'mount', '-o', 'ro', child_path]) mounted_volumes = get_mounted_volumes()
report.append([child_path, 'CS'])
except subprocess.CalledProcessError:
report.append([child_path, 'NS'])
# Update list of mounted devices # Loop over volumes
mounted_data = get_mounted_data() for vol_path, vol_data in volumes.items():
mounted_list = [m['source'] for m in mounted_data.values()] vol_data['show_data'] = {
'message': vol_path.replace('/dev/mapper/', ''),
# Update report lines for show_data() 'data': None,
for line in report: }
_path = line[0] if re.search(r'^loop\d', vol_path, re.IGNORECASE):
_result = line[1] # Skip loopback devices
info = {'message': '{}:'.format(_path)} vol_data['show_data']['data'] = 'Skipped'
if _path in mounted_list: vol_data['show_data']['warning'] = True
info['data'] = 'Mounted on {}'.format( report[vol_path] = vol_data
mounted_data[_path]['target']) elif 'children' in vol_data:
info['data'] = '{:40} ({} used, {} free)'.format( # Skip LVM/RAID partitions (the real volume is mounted separately)
info['data'], vol_data['show_data']['data'] = vol_data.get('fstype', 'UNKNOWN')
human_readable_size(mounted_data[_path]['used']), if vol_data.get('label', None):
human_readable_size(mounted_data[_path]['avail'])) vol_data['show_data']['data'] += ' "{}"'.format(vol_data['label'])
if _result == 'Already Mounted': vol_data['show_data']['info'] = True
info['warning'] = True report[vol_path] = vol_data
elif _result == 'Skipped':
info['data'] = 'Skipped'
info['warning'] = True
else: else:
info['data'] = 'Failed to mount' if vol_path in mounted_volumes:
info['error'] = True vol_data['show_data']['warning'] = True
line.append(info) else:
# Mount volume
try:
run_program(['udevil', 'mount', '-o', 'ro', vol_path])
except subprocess.CalledProcessError:
vol_data['show_data']['data'] = 'Failed to mount'
vol_data['show_data']['error'] = True
# Update mounted_volumes data
mounted_volumes = get_mounted_volumes()
# Format pretty result string
if vol_data['show_data']['data'] != 'Failed to mount':
size_used = human_readable_size(
mounted_volumes[vol_path]['used'])
size_avail = human_readable_size(
mounted_volumes[vol_path]['avail'])
vol_data['show_data']['data'] = 'Mounted on {}'.format(
mounted_volumes[vol_path]['target'])
vol_data['show_data']['data'] = '{:40} ({} used, {} free)'.format(
vol_data['show_data']['data'],
size_used,
size_avail)
# Update report
report[vol_path] = vol_data
return report return report
def mount_backup_shares(read_write=False): def mount_backup_shares(read_write=False):
"""Mount the backup shares unless labeled as already mounted.""" """Mount the backup shares unless labeled as already mounted."""
if psutil.LINUX: if psutil.LINUX:
mounted_data = get_mounted_data() mounted_volumes = get_mounted_volumes()
for server in BACKUP_SERVERS: for server in BACKUP_SERVERS:
if psutil.LINUX: if psutil.LINUX:
# Update mounted status # Update mounted status
source = '//{IP}/{Share}'.format(**server) source = '//{IP}/{Share}'.format(**server)
dest = '/Backups/{Name}'.format(**server) dest = '/Backups/{Name}'.format(**server)
mounted_str = '(Already) Mounted {}'.format(dest) mounted_str = '(Already) Mounted {}'.format(dest)
data = mounted_data.get(source, {}) data = mounted_volumes.get(source, {})
if dest == data.get('target', ''): if dest == data.get('target', ''):
server['Mounted'] = True server['Mounted'] = True
elif psutil.WINDOWS: elif psutil.WINDOWS:

View file

@ -22,8 +22,8 @@ if __name__ == '__main__':
# Print report # Print report
print_info('\nResults') print_info('\nResults')
for line in report: for vol_name, vol_data in sorted(report.items()):
show_data(indent=4, width=16, **line[-1]) show_data(indent=4, width=20, **vol_data['show_data'])
# Done # Done
print_standard('\nDone.') print_standard('\nDone.')