Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,7 @@ A xapi plugin to get the lsblk output on the host.
### `list_block_devices`:
```
$ xe host-call-plugin host-uuid=<uuid> plugin=lsblk.py fn=list_block_devices
{
"blockdevices": [{"kname": "sdb", "name": "sdb", "pkname": "", "mountpoint": "", "ro": "0", "type": "disk", "size": "64424509440"}, {"kname": "sda", "name": "sda", "pkname": "", "mountpoint": "", "ro": "0", "type": "disk", "children": [{"kname": "sda4", "name": "sda4", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", "size": "536870912"}, {"kname": "sda2", "name": "sda2", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", "size": "19327352832"}, {"kname": "sda5", "name": "sda5", "pkname": "sda", "mountpoint": "/var/log", "ro": "0", "type": "part", "size": "4294967296"}, {"kname": "sda3", "name": "sda3", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", "children": [{"kname": "dm-0", "name": "XSLocalEXT--1fad55d2--4f07--8145--c78a--297b173e06b0-1fad55d2--4f07--8145--c78a--297b173e06b0", "pkname": "sda3", "mountpoint": "/run/sr-mount/1fad55d2-4f07-8145-c78a-297b173e06b0", "ro": "0", "type": "lvm", "size": "19847446528"}], "size": "19863158272"}, {"kname": "sda1", "name": "sda1", "pkname": "sda", "mountpoint": "/", "ro": "0", "type": "part", "size": "19327352832"}, {"kname": "sda6", "name": "sda6", "pkname": "sda", "mountpoint": "[SWAP]", "ro": "0", "type": "part", "size": "1073741824"}], "size": "64424509440"}]
}
{"blockdevices": [{"kname": "sda", "name": "sda", "pkname": "", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429"], "mountpoint": "", "ro": "0", "type": "disk", "children": [{"kname": "sda4", "name": "sda4", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part4", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part4"], "mountpoint": "", "ro": "0", "type": "part", "size": "536870912"}, {"kname": "sda2", "name": "sda2", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part2", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part2"], "mountpoint": "", "ro": "0", "type": "part", "size": "19327352832"}, {"kname": "sda5", "name": "sda5", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part5", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part5"], "mountpoint": "/var/log", "ro": "0", "type": "part", "size": "4294967296"}, {"kname": "sda3", "name": "sda3", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part3", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part3"], "mountpoint": "", "ro": "0", "type": "part", "size": "194883075584"}, {"kname": "sda1", "name": "sda1", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part1", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part1"], "mountpoint": "/", "ro": "0", "type": "part", "size": "19327352832"}, {"kname": "sda6", "name": "sda6", "pkname": "sda", "device-id-paths": ["/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429-part6", "/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429-part6"], "mountpoint": "[SWAP]", "ro": "0", "type": "part", "size": "1073741824"}], "size": "239444426752"}]}
```
- `blockdevices` is a json representation of the blockdevices.
- `stdout` is the raw output.
Expand Down
47 changes: 28 additions & 19 deletions SOURCES/etc/xapi.d/plugins/lsblk.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,37 @@

from xcpngutils import run_command, error_wrapped

LSBLK_COLUMNS = "NAME,KNAME,PKNAME,SIZE,TYPE,RO,MOUNTPOINT"

def _run(cmd):
"""Small helper to run a [cmd, ...] and get its decoded and stripped output."""
return run_command(cmd)["stdout"].decode("utf-8").strip()

def udev_export_db():
"""Check udev database to extract a dict of {device_name: [list, of, symlinks], ...}."""
return {
re.search(r'N: (.*)', device).group(1):
sorted("/dev/" + path for path in re.findall(r'S: (disk/.*)', device))
for device in _run(["udevadm", "info", "--export-db"]).split("\n\n")
if "S: disk/" in device and "N: " in device
}

@error_wrapped
def list_block_devices(session, args):
result = run_command(["lsblk", "-P", "-b", "-o", "NAME,KNAME,PKNAME,SIZE,TYPE,RO,MOUNTPOINT"])
output_string = result["stdout"].decode("utf-8").strip()

results = list()
blockdevices = dict()
for output in output_string.split("\n"):
output_dict = dict(re.findall(r'(\S+)=(".*?"|\S+)', output))
output_dict = {key.lower(): output_dict[key].strip('"') for key in output_dict}
kname = output_dict["kname"]
pkname = output_dict["pkname"]
if pkname != "":
parent = blockdevices[pkname]
if "children" not in parent:
parent["children"] = list()
parent["children"].append(output_dict)
results = []
blockdevices = {}
symlinks = udev_export_db()
for output in _run(["lsblk", "-P", "-b", "-o", LSBLK_COLUMNS]).splitlines():
device = {
key.lower(): value.strip('"')
for key, value in re.findall(r'(\S+)=(".*?"|\S+)', output)
}
device["device-id-paths"] = symlinks.get(device["kname"], [])
if device["pkname"]:
blockdevices[device["pkname"]].setdefault("children", []).append(device)
else:
results.append(output_dict)

blockdevices[kname] = output_dict

results.append(device)
blockdevices[device["kname"]] = device
return json.dumps({'blockdevices': results})

if __name__ == "__main__":
Expand Down
58 changes: 43 additions & 15 deletions tests/test_lsblk.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@mock.patch('lsblk.run_command', autospec=True)
class TestListBlockDevices:
def test_lsblk(self, run_command):
run_command.return_value = {
lsblk_return_value = {
"stdout": b'''NAME="sdb" KNAME="sdb" PKNAME="" SIZE="64424509440" TYPE="disk" RO="0" MOUNTPOINT=""
NAME="sda" KNAME="sda" PKNAME="" SIZE="64424509440" TYPE="disk" RO="0" MOUNTPOINT=""
NAME="sda4" KNAME="sda4" PKNAME="sda" SIZE="536870912" TYPE="part" RO="0" MOUNTPOINT=""
Expand All @@ -19,32 +19,60 @@ def test_lsblk(self, run_command):
PKNAME="sda3" SIZE="19847446528" TYPE="lvm" RO="0" MOUNTPOINT="/run/sr-mount/1fad55d2-4f07-8145-c78a-297b173e06b0"
NAME="sda1" KNAME="sda1" PKNAME="sda" SIZE="19327352832" TYPE="part" RO="0" MOUNTPOINT="/"
NAME="sda6" KNAME="sda6" PKNAME="sda" SIZE="1073741824" TYPE="part" RO="0" MOUNTPOINT="[SWAP]"'''}
udevadm_return_value = {
"stdout": b"\n\n".join(
b"\n".join([
b'''N: ''' + dev,
b'''S: disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429''',
b'''S: disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429''',
])
for dev in (b"sdb", b"sda", b"sda1", b"sda2", b"sda3", b"sda4", b"sda5", b"sda6", b"dm-0"))
}

def mock_run_command(command):
if command[0] == "lsblk":
assert command == ["lsblk", "-P", "-b", "-o", "NAME,KNAME,PKNAME,SIZE,TYPE,RO,MOUNTPOINT"]
return lsblk_return_value
if command[0] == "udevadm":
return udevadm_return_value
run_command.side_effect = mock_run_command

expected = ' \
{"blockdevices": [{"kname": "sdb", "name": "sdb", "pkname": "", "mountpoint": "", "ro": "0", "type": \
"disk", "size": "64424509440"}, {"kname": "sda", "name": "sda", "pkname": "", "mountpoint": "", "ro": "0", "type": \
"disk", "children": [{"kname": "sda4", "name": "sda4", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", \
"size": "536870912"}, {"kname": "sda2", "name": "sda2", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", \
"size": "19327352832"}, {"kname": "sda5", "name": "sda5", "pkname": "sda", "mountpoint": "/var/log", "ro": "0", \
"type": "part", "size": "4294967296"}, {"kname": "sda3", "name": "sda3", "pkname": "sda", "mountpoint": "", "ro": "0", \
"type": "part", "children": [{"kname": "dm-0", "name": \
"disk", "size": "64424509440", "device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, {"kname": "sda", "name": "sda", "pkname": "", \
"mountpoint": "", "ro": "0", "type": "disk", \
"children": [{"kname": "sda4", "name": "sda4", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", \
"size": "536870912", "device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, \
{"kname": "sda2", "name": "sda2", "pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", \
"size": "19327352832", "device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, {"kname": "sda5", "name": "sda5", \
"pkname": "sda", "mountpoint": "/var/log", "ro": "0", "type": "part", "size": "4294967296", \
"device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, {"kname": "sda3", "name": "sda3", \
"pkname": "sda", "mountpoint": "", "ro": "0", "type": "part", "children": [{"kname": "dm-0", "name": \
"XSLocalEXT--1fad55d2--4f07--8145--c78a--297b173e06b0-1fad55d2--4f07--8145--c78a--297b173e06b0", "pkname": "sda3", \
"mountpoint": "/run/sr-mount/1fad55d2-4f07-8145-c78a-297b173e06b0", "ro": "0", "type": "lvm", "size": "19847446528"}], \
"size": "19863158272"}, {"kname": "sda1", "name": "sda1", "pkname": "sda", "mountpoint": "/", "ro": "0", "type": \
"part", "size": "19327352832"}, {"kname": "sda6", "name": "sda6", "pkname": "sda", "mountpoint": "[SWAP]", "ro": "0", \
"type": "part", "size": "1073741824"}], "size": "64424509440"}]}'
"mountpoint": "/run/sr-mount/1fad55d2-4f07-8145-c78a-297b173e06b0", "ro": "0", "type": "lvm", "size": "19847446528", \
"device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}], "size": "19863158272", "device-id-paths": \
["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", "/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, \
{"kname": "sda1", "name": "sda1", "pkname": "sda", "mountpoint": "/", "ro": "0", "type": \
"part", "size": "19327352832", "device-id-paths": ["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}, {"kname": "sda6", "name": "sda6", "pkname": "sda", \
"mountpoint": "[SWAP]", "ro": "0", "type": "part", "size": "1073741824", "device-id-paths": \
["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", \
"/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}], "size": "64424509440", "device-id-paths": \
["/dev/disk/by-id/scsi-36c81f660e6c1d5002a0a4ad00dacf429", "/dev/disk/by-id/wwn-0x6c81f660e6c1d5002a0a4ad00dacf429"]}]}'
res = list_block_devices(None, None)

assert json.loads(res) == json.loads(expected)
run_command.assert_called_once_with(["lsblk", "-P", "-b", "-o", "NAME,KNAME,PKNAME,SIZE,TYPE,RO,MOUNTPOINT"])

def test_lsblk_error(self, run_command):
run_command.side_effect = Exception('Error!')

with pytest.raises(XenAPIPlugin.Failure) as e:
list_block_devices(None, None)
run_command.assert_called_once_with(
["lsblk", "-P", "-b", "-o", "NAME,KNAME,PKNAME,SIZE,TYPE,RO,MOUNTPOINT"]
)
run_command.assert_called_once_with(["udevadm", "info", "--export-db"])
assert e.value.params[0] == '-1'
assert e.value.params[1] == 'Error!'
Loading