Skip to content

Instantly share code, notes, and snippets.

@mcrosson
Created February 1, 2015 21:34
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mcrosson/cac0bbb04d22f45a4c67 to your computer and use it in GitHub Desktop.
#!/usr/bin/python2
# -*- coding: utf-8 -*-
from __future__ import print_function
import subprocess, pprint, json
from collections import defaultdict
btrfs_bin = '/sbin/btrfs'
filesystems = []
label = None
uuid = None
devices = None
devid = None
path = None
filesystem = {}
cmd = subprocess.Popen([btrfs_bin, 'fi', 'show', '--all-devices'], stdout=subprocess.PIPE)
for line in cmd.stdout:
set_values = False
line = line.strip().split()
if len(line) < 1:
continue
if line[0].startswith('Label'):
label = line[1]
uuid = line[3]
elif line[0].startswith('Total'):
devices = line[2]
elif line[0].startswith('devid'):
devid = line[1]
path = line[7]
set_values = True
if set_values:
filesystem['uuid'] = uuid
filesystem['label'] = label
filesystem['devices'] = devices
filesystem['devid'] = devid
filesystem['path'] = path
filesystems.append(filesystem)
cmd = subprocess.Popen([btrfs_bin, 'fi', 'show', '--mounted'], stdout=subprocess.PIPE)
for line in cmd.stdout:
line = line.strip().split()
if len(line) < 1:
continue
if line[0].startswith('Label'):
for filesystem in filesystems:
if filesystem['uuid'] == line[3]:
filesystem['mounted'] = True
break
cmd = subprocess.Popen(['/bin/mount'], stdout=subprocess.PIPE)
cmd = subprocess.Popen(['/bin/grep', 'btrfs'], stdin=cmd.stdout, stdout=subprocess.PIPE)
for line in cmd.stdout:
mount_info = {}
line = line.strip().split()
mount_info['device'] = line[0]
mount_info['mountpoint'] = line[2]
opts = line[5].strip('(').strip(')').split(',')
for opt in opts:
if opt.startswith('subvol'):
mount_info['subvol'] = opt[7:]
opts.remove(opt)
mount_info['opts'] = opts
blk_uuid = None
cmd = subprocess.Popen(['/sbin/blkid', mount_info['device']], stdout=subprocess.PIPE)
for line in cmd.stdout:
line = line.strip()
if len(line) > 0:
line = line.split()
blk_uuid = line[1].strip('UUID=').strip('"')
filesystem = None
for fs in filesystems:
if fs['uuid'] == blk_uuid:
filesystem = fs
break
mounts = []
if filesystem.has_key('mounts'):
mounts = filesystem['mounts']
mounts.append(mount_info)
filesystem['mounts'] = mounts
for filesystem in filesystems:
subvols = {}
if filesystem.has_key('mounted') and filesystem['mounted'] is True:
cmd = subprocess.Popen([btrfs_bin, 'subvolume', 'list', fs['mounts'][0]['mountpoint']], stdout=subprocess.PIPE)
for line in cmd.stdout:
line = line.strip().split()
subvol = {}
subvol['id'] = line[1]
subvol['top_level'] = line[6]
subvol['path'] = line[-1]
subvols[subvol['id']] = subvol
mounts = fs['mounts']
for mount in mounts:
sid = None
uuid = None
parent = None
parent_uuid = None
top_level = None
flags = None
cmd = subprocess.Popen([btrfs_bin, 'subvolume', 'show', mount['mountpoint']], stdout=subprocess.PIPE)
for line in cmd.stdout:
line = line.strip().split(':')
if len(line) < 2:
continue
if line[0].startswith('Object'):
sid = line[1].strip()
elif line[0].startswith('uuid'):
uuid = line[1].strip()
elif line[0].startswith('Parent'):
if 'uuid' in line[0]:
parent_uuid = line[1].strip()
else:
parent = line[1].strip()
elif line[0].startswith('Top Level'):
top_level = line[1].strip()
elif line[0].startswith('Flags'):
flags = line[1].strip()
subvol = subvols[sid]
subvol['uuid'] = uuid
subvol['parent'] = parent
subvol['parent_uuid'] = parent_uuid
subvol['top_level'] = top_level
subvol['flags'] = flags
fs['subvols'] = subvols
print(json.dumps(filesystems, indent=1))
#!/usr/bin/python2
# -*- coding: utf-8 -*-
# {{ ansible_managed }}
from __future__ import print_function
import subprocess, re, pprint, json, glob
from collections import defaultdict
arrays = []
for array in glob.glob('/dev/md?'):
device = array.strip()
name = array.split('/')[-1]
array = {}
array['dev_name'] = name
array['device'] = device
array['devices'] = {}
info = subprocess.Popen(['/sbin/mdadm', '-D', device], stdout=subprocess.PIPE)
for line in info.stdout:
line = line.strip()
if len(line) < 1:
continue
values = line.split(':')
key = values[0].strip()
if key.startswith('/dev/') or key.startswith('Creation') or key.startswith('Array Size') or key.startswith('Used Dev') or key.startswith('Persistence') or key.startswith('Update Time') or key.startswith('Number '):
continue
value = None
if len(values) < 2:
devices = array['devices']
values = key.split()
device = values[-1]
devices[device] = {}
devices[device]['number'] = values[0]
devices[device]['major'] = values[1]
devices[device]['minor'] = values[2]
devices[device]['raid_device'] = values[3]
devices[device]['state'] = ','.join(values[4:-1])
else:
value = ':'.join(values[1:]).strip()
array[key] = value
arrays.append(array)
print(json.dumps(arrays, indent=1))
#!/usr/bin/python2
# -*- coding: utf-8 -*-
# {{ ansible_managed }}
from __future__ import print_function
import subprocess, re, pprint, json
from collections import defaultdict
def print_tab():
print(' ', end='')
zpool_bin = '/sbin/zpool'
sudo_bin = '/usr/bin/sudo'
cut_bin = '/usr/bin/cut'
pools = []
cmd = subprocess.Popen([zpool_bin, 'list', '-H'], stdout=subprocess.PIPE)
cmd = subprocess.Popen([cut_bin, '-f1'], stdin=cmd.stdout, stdout=subprocess.PIPE)
for line in cmd.stdout:
pool = {}
pool['name'] = line.strip()
pools.append(pool)
for pool in pools:
zpool_cmd_list = [sudo_bin, zpool_bin, 'status', pool['name']]
zpool_status = subprocess.Popen(zpool_cmd_list, stdout=subprocess.PIPE)
status = defaultdict(lambda: defaultdict(str))
disks = []
critical_errors = []
total_errors = 0
error_flag = False
has_text = re.compile('\D+') # any non digit
for line in zpool_status.stdout:
line = line.strip()
if line.startswith('scsi') or line.startswith('ad') or line.startswith('da') or line.startswith('sd') or 'luks' in line or 'zfs' in line or 'crypt' in line:
values = line.split()
disk = values[0]
read_err = values[2]
disks.append(disk)
if 'UNAVAIL' in line:
critical_errors.append(disk)
continue
# Do some string checks in case number of errors climbs to high (e.g. 2.15k)
if re.search(has_text, read_err) is not None or int(read_err) > 0:
error_flag = True
total_errors += int(read_err)
write_err = values[3]
if re.search(has_text, write_err) is not None or int(write_err) > 0:
error_flag = True
total_errors += int(write_err)
chksum_err = values[4]
if re.search(has_text, chksum_err) is not None or int(chksum_err) > 0:
error_flag = True
total_errors += int(chksum_err)
status[disk]['read'] = read_err
status[disk]['write'] = write_err
status[disk]['chksum'] = chksum_err
pool['disks'] = disks
pool['status'] = status
pool['critical_errors'] = critical_errors
pool['total_errors'] = total_errors
pool['error_flag'] = error_flag
print(json.dumps(pools, indent=1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment