diff --git a/README.md b/README.md index a8e8385..71bd8a8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,83 @@ $ xe host-call-plugin host-uuid= plugin=zfs.py fn=list_zfs_pools ``` (the most pertinent parameter is `mountpoint`) +## XCP-ng Kalray DPU + +A xapi plugin to get information about raids, logical volume store (LVS) and +devices that are present on the Kalray DPU. It also allow the management of +logical volumes (LV): creation and deletion. Parameters depends of the name of +the command some are always available: + - *username*: username to use to connect to DPU (required) + - *password*: password to connect to DPU (required) + - *server*: IP of the server for configuring the DPU (default: localhost) + - *port*: Port to use (default: 8080) + - *timeout*: timeout in second (default: 60.0) + +## Command details + +### Block devices +#### Get the list of devices on the Kalray DPU +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=get_devices \ + args:username= args:password= +{"status": "ok", "output": [{"name": "HotInNvmeWDS500AFY0-22050C800415n1", "aliases": [], "product_name": "NVMe disk", "block_size": 512, "num_blocks": 976773168, "uuid": "e8238fa6-bf53-0001-001b-448b45afa6a7", "assigned_rate_limits": {"rw_ios_per_sec": 0, "rw_mbytes_per_sec": 0, "r_mbytes_per_sec": 0, "w_mbytes_per_sec": 0}, "claimed": false, "zoned": false, "supported_io_types": {"read": true, "write": true, "unmap": true, "write_zeroes": true, "flush": true, "reset": true, "nvme_admin": true, "nvme_io": true}, "driver_specific": {"nvme": [{"pci_address": "0000:00:00.0", "trid": {"trtype": "PCIe", "traddr": "0000:00:00.0"}, "ctrlr_data": {"cntlid": 8224, "vendor_id": "0x15b7", "model_number": "WDS500G1X0E-00AFY0", "serial_number": "22050C800415", "firmware_revision": "614900WD", "subnqn": "nqn.2018-01.com.wdc:nguid:E8238FA6BF53-0001-001B448B45AFA6A7", "oacs": {"security": 1, "format": 1, "firmware": 1, "ns_manage": 0}, "multi_ctrlr": false, "ana_reporting": false}, "vs": {"nvme_version": "1.4"}, "ns_data": {"id": 1, "can_share": false}, "security": {"opal": false}}], "mp_policy": "active_passive"}}]} +``` + +### RAID +#### Create a raid on the Kalray DPU +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=create_raid \ + args:username= args:password= \ + args:base_bdevs=HotInNvmeWDS500AFY0-22050C800415n1,HotInNvmeWDS500AFY0-22050C800378n1 \ + args:raid_name=raid0 \ + args:raid_level=raid0 +true +``` + +#### Get the list of raids on the Kalray DPU +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=get_raids \ + args:username= args:password= +["raid0"] +``` + +### Logical Volume Store +#### Create an LVS on the Kalray DPU +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=create_lvs \ + args:username= args:password= \ + args:lvs_name=lvs \ + args:bdev_name=raid0 +"6fb90332-56e4-4d03-aa6a-f858a2c2ca97" +``` + +#### Get the list of LVS on the Kalray DPU +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=get_lvs \ + args:username= args:password= +[{"uuid": "6fb90332-56e4-4d03-aa6a-f858a2c2ca97", "name": "lvs", "passive": false, "base_bdev": "raid0", "total_data_clusters": 29804, "free_clusters": 29772, "block_size": 512, "cluster_size": 33554432}] +``` + +### Logical Volume +#### Create a new logical volume +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=create_lvol \ + args:username= args:password= \ + args:lvol_name=volume_09 \ + args:lvol_size_mb=1048576 \ + args:lvs_name=lvs +"6c84b44c-a61b-41a4-8b19-32ab643b57d9" +``` + +#### Delete a logical volume +``` +$ xe host-call-plugin host-uuid= plugin=kalray_dpu.py fn=delete_lvol \ + args:username= args:password= \ + args:lvol_name= +Error code: -1 +Error parameters: Deletion of lvol is not yet implemented +``` + ## XCP-ng LVM A xapi plugin to list, create and destroy PVs, VGs and LVMs on a host. diff --git a/SOURCES/etc/xapi.d/plugins/kalray_dpu.py b/SOURCES/etc/xapi.d/plugins/kalray_dpu.py new file mode 100755 index 0000000..6a23d2c --- /dev/null +++ b/SOURCES/etc/xapi.d/plugins/kalray_dpu.py @@ -0,0 +1,147 @@ +#!/usr/bin/python3 +"""XAPI plugin to manage Kalray DPU.""" + +import json +import XenAPIPlugin # pylint: disable=import-error + +from kalray.acs.spdk import rpc # pylint: disable=import-error +from xcpngutils import error_wrapped + +class KalrayCmd: + """Describe a command to be ran on the Kalray DPU.""" + + def __init__(self, rpc_name: str, updates: dict): + self.server = 'localhost' + self.port = 8080 + self.username = None + self.password = None + self.timeout = 60.0 + self.rpc_name = rpc_name + self.rpc_params = {} # will be updated using add_rpc_params + + for k, v in updates.items(): + if hasattr(self, k): + setattr(self, k, v) + + # Check that username & password are well set + if self.username is None: + raise XenAPIPlugin.Failure("-1", ["'username' is required"]) + if self.password is None: + raise XenAPIPlugin.Failure("-1", ["'password' is required"]) + + def add_rpc_params(self, key, value): + """Adds a parameter that will be passed to the RPC.""" + self.rpc_params[key] = value + + def call_rpc(self): + """Do the RPC call.""" + try: + client = rpc.client.HTTPJSONRPCClient( + self.server, + self.port, + self.timeout, + self.username, + self.password, + log_level="ERROR") + message = client.call(self.rpc_name, self.rpc_params) + except rpc.client.JSONRPCException as exc: + raise XenAPIPlugin.Failure("-1", [exc.message]) + + return json.dumps(message) + +@error_wrapped +def get_devices(_session, args): + """Get the list of devices available on the Kalray DPU.""" + kc = KalrayCmd("bdev_get_bdevs", args) + return kc.call_rpc() + +@error_wrapped +def create_raid(_session, args): + """Create a raid.""" + kc = KalrayCmd("bdev_raid_create", args) + try: + raid_name = args["raid_name"] + raid_level = args["raid_level"] + base_bdevs = args["base_bdevs"] + except KeyError as msg: + raise XenAPIPlugin.Failure("-1", [f"Key {msg} is missing"]) + + # Sanity checks + if raid_level not in ["raid0", "raid1", "raid10"]: + raise XenAPIPlugin.Failure("-1", ["Only raid0, raid1 and raid10 are supported"]) + # TODO: check that bdevs are "NVMe disk" + + kc.add_rpc_params("name", raid_name) + kc.add_rpc_params("raid_level", raid_level) + kc.add_rpc_params("base_bdevs", base_bdevs.split(',')) + kc.add_rpc_params("strip_size_kb", 128) + kc.add_rpc_params("persist", True) + kc.add_rpc_params("split_dp", True) + return kc.call_rpc() + +@error_wrapped +def get_raids(_session, args): + """Get the list of raids available on the Kalray DPU.""" + kc = KalrayCmd("bdev_raid_get_bdevs", args) + kc.add_rpc_params("category", "all") + return kc.call_rpc() + +@error_wrapped +def create_lvs(_session, args): + """Create a logical volume store.""" + kc = KalrayCmd("bdev_lvol_create_lvstore", args) + try: + lvs_name = args["lvs_name"] + bdev_name = args["bdev_name"] + except KeyError as msg: + raise XenAPIPlugin.Failure("-1", [f"Key {msg} is missing"]) + + kc.add_rpc_params("lvs_name", lvs_name) + kc.add_rpc_params("bdev_name", bdev_name) + + return kc.call_rpc() + +@error_wrapped +def get_lvs(_session, args): + """Get the list of logical volume stores available on the Kalray DPU.""" + kc = KalrayCmd("bdev_lvol_get_lvstores", args) + return kc.call_rpc() + +@error_wrapped +def create_lvol(_session, args): + """Create a new lvol on the Kalray DPU.""" + kc = KalrayCmd("bdev_lvol_create", args) + + try: + lvol_name = args["lvol_name"] + lvol_size = int(args["lvol_size_mb"]) + lvs_name = args["lvs_name"] + except KeyError as msg: + raise XenAPIPlugin.Failure("-1", [f"Key {msg} is missing"]) + except ValueError as msg: + raise XenAPIPlugin.Failure("-1", [f"Wrong size: {msg}"]) + + kc.add_rpc_params("lvol_name", lvol_name) + kc.add_rpc_params("size", lvol_size) + kc.add_rpc_params("lvs_name", lvs_name) + return kc.call_rpc() + +@error_wrapped +def delete_lvol(_session, args): + """Delete the lvol passed as parameter on the Kalray DPU if exists.""" + try: + lvol_name = args["lvol_name"] + raise XenAPIPlugin.Failure("-1", [f"Deletion of lvol {lvol_name} is not yet implemented"]) + except KeyError as exc: + raise XenAPIPlugin.Failure("-1", ["No argument found with key 'name'."]) from exc + +if __name__ == "__main__": + XenAPIPlugin.dispatch({ + "get_devices": get_devices, + "create_raid": create_raid, + "get_raids": get_raids, + "create_lvs": create_lvs, + "get_lvs": get_lvs, + "create_lvol": create_lvol, + "delete_lvol": delete_lvol, + })