summaryrefslogtreecommitdiffstats
path: root/src/spdk/scripts/spdkcli/ui_node.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/spdk/scripts/spdkcli/ui_node.py929
1 files changed, 929 insertions, 0 deletions
diff --git a/src/spdk/scripts/spdkcli/ui_node.py b/src/spdk/scripts/spdkcli/ui_node.py
new file mode 100644
index 00000000..43f6bdfc
--- /dev/null
+++ b/src/spdk/scripts/spdkcli/ui_node.py
@@ -0,0 +1,929 @@
+from configshell_fb import ConfigNode, ExecutionError
+from uuid import UUID
+from rpc.client import JSONRPCException
+import json
+
+
+def convert_bytes_to_human(size):
+ if not size:
+ return ""
+ for x in ["bytes", "K", "M", "G", "T"]:
+ if size < 1024.0:
+ return "%3.1f%s" % (size, x)
+ size /= 1024.0
+
+
+class UINode(ConfigNode):
+ def __init__(self, name, parent=None, shell=None):
+ ConfigNode.__init__(self, name, parent, shell)
+
+ def refresh(self):
+ for child in self.children:
+ child.refresh()
+
+ def ui_command_refresh(self):
+ self.refresh()
+
+ def ui_command_ll(self, path=None, depth=None):
+ """
+ Alias for ls.
+ """
+ self.ui_command_ls(path, depth)
+
+ def execute_command(self, command, pparams=[], kparams={}):
+ try:
+ result = ConfigNode.execute_command(self, command,
+ pparams, kparams)
+ except Exception as msg:
+ self.shell.log.error(str(msg))
+ pass
+ else:
+ self.shell.log.debug("Command %s succeeded." % command)
+ return result
+
+
+class UIBdevs(UINode):
+ def __init__(self, parent):
+ UINode.__init__(self, "bdevs", parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ UIMallocBdev(self)
+ UIAIOBdev(self)
+ UILvolBdev(self)
+ UINvmeBdev(self)
+ UINullBdev(self)
+ UIErrorBdev(self)
+ UISplitBdev(self)
+ UIPmemBdev(self)
+ UIRbdBdev(self)
+ UIiSCSIBdev(self)
+ UIVirtioBlkBdev(self)
+ UIVirtioScsiBdev(self)
+
+
+class UILvolStores(UINode):
+ def __init__(self, parent):
+ UINode.__init__(self, "lvol_stores", parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for lvs in self.get_root().get_lvol_stores():
+ UILvsObj(lvs, self)
+
+ def ui_command_create(self, name, bdev_name, cluster_size=None):
+ """
+ Creates logical volume store on target bdev.
+
+ Arguments:
+ name - Friendly name to use alongside with UUID identifier.
+ bdev_name - On which bdev to create the lvol store.
+ cluster_size - Cluster size to use when creating lvol store, in bytes. Default: 4194304.
+ """
+
+ cluster_size = self.ui_eval_param(cluster_size, "number", None)
+
+ try:
+ self.get_root().create_lvol_store(lvs_name=name, bdev_name=bdev_name, cluster_sz=cluster_size)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name=None, uuid=None):
+ """
+ Deletes logical volume store from configuration.
+ This will also delete all logical volume bdevs created on this lvol store!
+
+ Arguments:
+ name - Friendly name of the logical volume store to be deleted.
+ uuid - UUID number of the logical volume store to be deleted.
+ """
+ if name is None and uuid is None:
+ self.shell.log.error("Please specify one of the identifiers: "
+ "lvol store name or UUID")
+ self.get_root().delete_lvol_store(lvs_name=name, uuid=uuid)
+ self.get_root().refresh()
+ self.refresh()
+
+ def summary(self):
+ return "Lvol stores: %s" % len(self.children), None
+
+
+class UIBdev(UINode):
+ def __init__(self, name, parent):
+ UINode.__init__(self, name, parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for bdev in self.get_root().get_bdevs(self.name):
+ UIBdevObj(bdev, self)
+
+ def ui_command_get_bdev_iostat(self, name=None):
+ try:
+ ret = self.get_root().get_bdevs_iostat(name=name)
+ self.shell.log.info(json.dumps(ret, indent=2))
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ def summary(self):
+ return "Bdevs: %d" % len(self.children), None
+
+
+class UIMallocBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "malloc", parent)
+
+ def ui_command_create(self, size, block_size, name=None, uuid=None):
+ """
+ Construct a Malloc bdev.
+
+ Arguments:
+ size - Size in megabytes.
+ block_size - Integer, block size to use when constructing bdev.
+ name - Optional argument. Custom name to use for bdev. If not provided
+ then name will be "MallocX" where X is next available ID.
+ uuid - Optional parameter. Custom UUID to use. If empty then random
+ will be generated.
+ """
+
+ size = self.ui_eval_param(size, "number", None)
+ block_size = self.ui_eval_param(block_size, "number", None)
+
+ try:
+ ret_name = self.get_root().create_malloc_bdev(num_blocks=size * 1024 * 1024 // block_size,
+ block_size=block_size,
+ name=name, uuid=uuid)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes malloc bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the malloc bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_malloc_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIAIOBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "aio", parent)
+
+ def ui_command_create(self, name, filename, block_size):
+ """
+ Construct an AIO bdev.
+ Backend file must exist before trying to create an AIO bdev.
+
+ Arguments:
+ name - Optional argument. Custom name to use for bdev. If not provided
+ then name will be "MallocX" where X is next available ID.
+ filename - Path to AIO backend.
+ block_size - Integer, block size to use when constructing bdev.
+ """
+
+ block_size = self.ui_eval_param(block_size, "number", None)
+
+ try:
+ ret_name = self.get_root().create_aio_bdev(name=name,
+ block_size=int(block_size),
+ filename=filename)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes aio bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the aio bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_aio_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UILvolBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "logical_volume", parent)
+
+ def ui_command_create(self, name, size, lvs, thin_provision=None):
+ """
+ Construct a Logical Volume bdev.
+
+ Arguments:
+ name - Friendly name to use for creating logical volume bdev.
+ size - Size in megabytes.
+ lvs - Identifier of logical volume store on which the bdev should be
+ created. Can be either a friendly name or UUID.
+ thin_provision - Whether the bdev should be thick or thin provisioned.
+ Default is False, and created bdevs are thick-provisioned.
+ """
+ uuid = None
+ lvs_name = None
+ try:
+ UUID(lvs)
+ uuid = lvs
+ except ValueError:
+ lvs_name = lvs
+
+ size = self.ui_eval_param(size, "number", None)
+ size *= (1024 * 1024)
+ thin_provision = self.ui_eval_param(thin_provision, "bool", False)
+
+ try:
+ ret_uuid = self.get_root().create_lvol_bdev(lvol_name=name, size=size,
+ lvs_name=lvs_name, uuid=uuid,
+ thin_provision=thin_provision)
+ self.shell.log.info(ret_uuid)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes lvol bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the lvol bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().destroy_lvol_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UINvmeBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "nvme", parent)
+
+ def ui_command_create(self, name, trtype, traddr,
+ adrfam=None, trsvcid=None, subnqn=None):
+
+ if "rdma" in trtype and None in [adrfam, trsvcid, subnqn]:
+ self.shell.log.error("Using RDMA transport type."
+ "Please provide arguments for adrfam, trsvcid and subnqn.")
+
+ try:
+ ret_name = self.get_root().create_nvme_bdev(name=name, trtype=trtype,
+ traddr=traddr, adrfam=adrfam,
+ trsvcid=trsvcid, subnqn=subnqn)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes NVMe controller from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the NVMe controller to be deleted.
+ """
+ try:
+ self.get_root().delete_nvme_controller(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UINullBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "null", parent)
+
+ def ui_command_create(self, name, size, block_size, uuid=None):
+ """
+ Construct a Null bdev.
+
+ Arguments:
+ name - Name to use for bdev.
+ size - Size in megabytes.
+ block_size - Integer, block size to use when constructing bdev.
+ uuid - Optional parameter. Custom UUID to use. If empty then random
+ will be generated.
+ """
+
+ size = self.ui_eval_param(size, "number", None)
+ block_size = self.ui_eval_param(block_size, "number", None)
+ num_blocks = size * 1024 * 1024 // block_size
+
+ try:
+ ret_name = self.get_root().create_null_bdev(num_blocks=num_blocks,
+ block_size=block_size,
+ name=name, uuid=uuid)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes null bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the null bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_null_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIErrorBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "error", parent)
+
+ def ui_command_create(self, base_name):
+ """
+ Construct a error injection bdev.
+
+ Arguments:
+ base_name - base bdev name on top of which error bdev will be created.
+ """
+
+ try:
+ self.get_root().create_error_bdev(base_name=base_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes error bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the error bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_error_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UISplitBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "split_disk", parent)
+
+ def ui_command_split_bdev(self, base_bdev, split_count, split_size_mb=None):
+ """
+ Construct split block devices from a base bdev.
+
+ Arguments:
+ base_bdev - Name of bdev to split
+ split_count - Number of split bdevs to create
+ split_size_mb- Size of each split volume in MiB (optional)
+ """
+
+ split_count = self.ui_eval_param(split_count, "number", None)
+ split_size_mb = self.ui_eval_param(split_size_mb, "number", None)
+
+ try:
+ ret_name = self.get_root().split_bdev(base_bdev=base_bdev,
+ split_count=split_count,
+ split_size_mb=split_size_mb)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.parent.refresh()
+ self.refresh()
+
+ def ui_command_destruct_split_bdev(self, base_bdev):
+ """Destroy split block devices associated with base bdev.
+
+ Args:
+ base_bdev: name of previously split bdev
+ """
+
+ try:
+ self.get_root().destruct_split_bdev(base_bdev=base_bdev)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.parent.refresh()
+ self.refresh()
+
+
+class UIPmemBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "pmemblk", parent)
+
+ def ui_command_create_pmem_pool(self, pmem_file, total_size, block_size):
+ total_size = self.ui_eval_param(total_size, "number", None)
+ block_size = self.ui_eval_param(block_size, "number", None)
+ num_blocks = int((total_size * 1024 * 1024) / block_size)
+
+ try:
+ self.get_root().create_pmem_pool(pmem_file=pmem_file,
+ num_blocks=num_blocks,
+ block_size=block_size)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ def ui_command_delete_pmem_pool(self, pmem_file):
+ try:
+ self.get_root().delete_pmem_pool(pmem_file=pmem_file)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ def ui_command_info_pmem_pool(self, pmem_file):
+ try:
+ ret = self.get_root().delete_pmem_pool(pmem_file=pmem_file)
+ self.shell.log.info(ret)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ def ui_command_create(self, pmem_file, name):
+ try:
+ ret_name = self.get_root().create_pmem_bdev(pmem_file=pmem_file,
+ name=name)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes pmem bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the pmem bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_pmem_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIRbdBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "rbd", parent)
+
+ def ui_command_create(self, pool_name, rbd_name, block_size, name=None):
+ block_size = self.ui_eval_param(block_size, "number", None)
+
+ try:
+ ret_name = self.get_root().create_rbd_bdev(pool_name=pool_name,
+ rbd_name=rbd_name,
+ block_size=block_size,
+ name=name)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes rbd bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the rbd bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().delete_rbd_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIiSCSIBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "iscsi", parent)
+
+ def ui_command_create(self, name, url, initiator_iqn):
+ """
+ Create iSCSI bdev in configuration by connecting to remote
+ iSCSI target.
+
+ Arguments:
+ name - name to be used as an ID for created iSCSI bdev.
+ url - iscsi url pointing to LUN on remote iSCSI target.
+ Example: iscsi://127.0.0.1:3260/iqn.2018-06.org.spdk/0.
+ initiator_iqn - IQN to use for initiating connection with the target.
+ """
+ try:
+ ret_name = self.get_root().create_iscsi_bdev(name=name,
+ url=url,
+ initiator_iqn=initiator_iqn)
+ self.shell.log.info(ret_name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes iSCSI bdev from configuration.
+
+ Arguments:
+ name - name of the iscsi bdev to be deleted.
+ """
+ try:
+ self.get_root().delete_iscsi_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIVirtioBlkBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "virtioblk_disk", parent)
+
+ def ui_command_create(self, name, trtype, traddr,
+ vq_count=None, vq_size=None):
+
+ vq_count = self.ui_eval_param(vq_count, "number", None)
+ vq_size = self.ui_eval_param(vq_size, "number", None)
+
+ try:
+ ret = self.get_root().create_virtio_dev(name=name,
+ trtype=trtype,
+ traddr=traddr,
+ dev_type="blk",
+ vq_count=vq_count,
+ vq_size=vq_size)
+
+ self.shell.log.info(ret)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Deletes virtio scsi bdev from configuration.
+
+ Arguments:
+ name - Is a unique identifier of the virtio scsi bdev to be deleted - UUID number or name alias.
+ """
+ try:
+ self.get_root().remove_virtio_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIVirtioScsiBdev(UIBdev):
+ def __init__(self, parent):
+ UIBdev.__init__(self, "virtioscsi_disk", parent)
+
+ def refresh(self):
+ self._children = set([])
+ for bdev in self.get_root().get_virtio_scsi_devs():
+ UIVirtioScsiBdevObj(bdev, self)
+
+ def ui_command_create(self, name, trtype, traddr,
+ vq_count=None, vq_size=None):
+
+ vq_count = self.ui_eval_param(vq_count, "number", None)
+ vq_size = self.ui_eval_param(vq_size, "number", None)
+
+ try:
+ ret = self.get_root().create_virtio_dev(name=name,
+ trtype=trtype,
+ traddr=traddr,
+ dev_type="scsi",
+ vq_count=vq_count,
+ vq_size=vq_size)
+
+ self.shell.log.info(ret)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ try:
+ self.get_root().remove_virtio_bdev(name=name)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIBdevObj(UINode):
+ def __init__(self, bdev, parent):
+ self.bdev = bdev
+ # Using bdev name also for lvol bdevs, which results in displying
+ # UUID instead of alias. This is because alias naming convention
+ # (lvol_store_name/lvol_bdev_name) conflicts with configshell paths
+ # ("/" as separator).
+ # Solution: show lvol alias in "summary field" for now.
+ # TODO: Possible next steps:
+ # - Either change default separator in tree for smth else
+ # - or add a UI command which would be able to autocomplete
+ # "cd" command based on objects alias and match is to the
+ # "main" bdev name.
+ UINode.__init__(self, self.bdev.name, parent)
+
+ def ui_command_show_details(self):
+ self.shell.log.info(json.dumps(vars(self.bdev), indent=2))
+
+ def summary(self):
+ size = convert_bytes_to_human(self.bdev.block_size * self.bdev.num_blocks)
+ size = "=".join(["Size", size])
+
+ in_use = "Not claimed"
+ if bool(self.bdev.claimed):
+ in_use = "Claimed"
+
+ alias = None
+ if self.bdev.aliases:
+ alias = self.bdev.aliases[0]
+
+ info = ", ".join([_f for _f in [alias, size, in_use] if _f])
+ return info, True
+
+
+class UIVirtioScsiBdevObj(UIBdevObj):
+ def __init__(self, bdev, parent):
+ UIBdevObj.__init__(self, bdev, parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for bdev in self.get_root().get_bdevs("virtio_scsi_disk"):
+ if self.bdev.name in bdev.name:
+ UIBdevObj(bdev, self)
+
+ def summary(self):
+ if "socket" in list(self.bdev.virtio.keys()):
+ info = self.bdev.virtio["socket"]
+ if "pci_address" in list(self.bdev.virtio.keys()):
+ info = self.bdev.virtio["pci_address"]
+ return info, True
+
+
+class UILvsObj(UINode):
+ def __init__(self, lvs, parent):
+ UINode.__init__(self, lvs.name, parent)
+ self.lvs = lvs
+
+ def ui_command_show_details(self):
+ self.shell.log.info(json.dumps(vars(self.lvs), indent=2))
+
+ def summary(self):
+ size = convert_bytes_to_human(self.lvs.total_data_clusters * self.lvs.cluster_size)
+ free = convert_bytes_to_human(self.lvs.free_clusters * self.lvs.cluster_size)
+ if not free:
+ free = "0"
+ size = "=".join(["Size", size])
+ free = "=".join(["Free", free])
+ info = ", ".join([str(size), str(free)])
+ return info, True
+
+
+class UIVhosts(UINode):
+ def __init__(self, parent):
+ UINode.__init__(self, "vhost", parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ self.get_root().list_vhost_ctrls()
+ UIVhostBlk(self)
+ UIVhostScsi(self)
+
+
+class UIVhost(UINode):
+ def __init__(self, name, parent):
+ UINode.__init__(self, name, parent)
+ self.refresh()
+
+ def ui_command_delete(self, name):
+ """
+ Delete a Vhost controller from configuration.
+
+ Arguments:
+ name - Controller name.
+ """
+ self.get_root().remove_vhost_controller(ctrlr=name)
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIVhostBlk(UIVhost):
+ def __init__(self, parent):
+ UIVhost.__init__(self, "block", parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for ctrlr in self.get_root().get_vhost_ctrlrs(self.name):
+ UIVhostBlkCtrlObj(ctrlr, self)
+
+ def ui_command_create(self, name, bdev, cpumask=None, readonly=False):
+ """
+ Construct a Vhost BLK controller.
+
+ Arguments:
+ name - Controller name.
+ bdev - Which bdev to attach to the controller.
+ cpumask - Optional. Integer to specify mask of CPUs to use.
+ Default: 1.
+ readonly - Whether controller should be read only or not.
+ Default: False.
+ """
+ try:
+ self.get_root().create_vhost_blk_controller(ctrlr=name,
+ dev_name=bdev,
+ cpumask=cpumask,
+ readonly=bool(readonly))
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIVhostScsi(UIVhost):
+ def __init__(self, parent):
+ UIVhost.__init__(self, "scsi", parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for ctrlr in self.get_root().get_vhost_ctrlrs(self.name):
+ UIVhostScsiCtrlObj(ctrlr, self)
+
+ def ui_command_create(self, name, cpumask=None):
+ """
+ Construct a Vhost SCSI controller.
+
+ Arguments:
+ name - Controller name.
+ cpumask - Optional. Integer to specify mask of CPUs to use.
+ Default: 1.
+ """
+ try:
+ self.get_root().create_vhost_scsi_controller(ctrlr=name,
+ cpumask=cpumask)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.get_root().refresh()
+ self.refresh()
+
+
+class UIVhostCtrl(UINode):
+ # Base class for SCSI and BLK controllers, do not instantiate
+ def __init__(self, ctrlr, parent):
+ self.ctrlr = ctrlr
+ UINode.__init__(self, self.ctrlr.ctrlr, parent)
+ self.refresh()
+
+ def ui_command_show_details(self):
+ self.shell.log.info(json.dumps(vars(self.ctrlr), indent=2))
+
+ def ui_command_set_coalescing(self, delay_base_us, iops_threshold):
+ delay_base_us = self.ui_eval_param(delay_base_us, "number", None)
+ iops_threshold = self.ui_eval_param(iops_threshold, "number", None)
+
+ try:
+ self.get_root().set_vhost_controller_coalescing(ctrlr=self.ctrlr.ctrlr,
+ delay_base_us=delay_base_us,
+ iops_threshold=iops_threshold)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+
+class UIVhostScsiCtrlObj(UIVhostCtrl):
+ def refresh(self):
+ self._children = set([])
+ for lun in self.ctrlr.backend_specific["scsi"]:
+ UIVhostTargetObj(lun, self)
+
+ def ui_command_remove_target(self, target_num):
+ """
+ Remove target node from SCSI controller.
+
+ Arguments:
+ target_num - Integer identifier of target node to delete.
+ """
+ try:
+ self.get_root().remove_vhost_scsi_target(ctrlr=self.ctrlr.ctrlr,
+ scsi_target_num=int(target_num))
+ for ctrlr in self.get_root().get_vhost_ctrlrs("scsi"):
+ if ctrlr.ctrlr == self.ctrlr.ctrlr:
+ self.ctrlr = ctrlr
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.refresh()
+ self.get_root().refresh()
+
+ def ui_command_add_lun(self, target_num, bdev_name):
+ """
+ Add LUN to SCSI target node.
+ Currently only one LUN (which is LUN ID 0) per target is supported.
+ Adding LUN to not existing target node will create that node.
+
+ Arguments:
+ target_num - Integer identifier of target node to modify.
+ bdev - Which bdev to add as LUN.
+ """
+ try:
+ self.get_root().add_vhost_scsi_lun(ctrlr=self.ctrlr.ctrlr,
+ scsi_target_num=int(target_num),
+ bdev_name=bdev_name)
+ for ctrlr in self.get_root().get_vhost_ctrlrs("scsi"):
+ if ctrlr.ctrlr == self.ctrlr.ctrlr:
+ self.ctrlr = ctrlr
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ self.refresh()
+
+ def summary(self):
+ info = self.ctrlr.socket
+ return info, True
+
+
+class UIVhostBlkCtrlObj(UIVhostCtrl):
+ def refresh(self):
+ self._children = set([])
+ UIVhostLunDevObj(self.ctrlr.backend_specific["block"]["bdev"], self)
+
+ def summary(self):
+ ro = None
+ if self.ctrlr.backend_specific["block"]["readonly"]:
+ ro = "Readonly"
+ info = ", ".join([_f for _f in [self.ctrlr.socket, ro] if _f])
+ return info, True
+
+
+class UIVhostTargetObj(UINode):
+ def __init__(self, target, parent):
+ self.target = target
+ # Next line: configshell does not allow paths with spaces.
+ UINode.__init__(self, target["target_name"].replace(" ", "_"), parent)
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ for target in self.target["luns"]:
+ UIVhostLunDevObj(target["bdev_name"], self)
+
+ def ui_command_show_details(self):
+ self.shell.log.info(json.dumps(self.target, indent=2))
+
+ def summary(self):
+ luns = "LUNs: %s" % len(self.target["luns"])
+ id = "TargetID: %s" % self.target["scsi_dev_num"]
+ info = ",".join([luns, id])
+ return info, True
+
+
+class UIVhostLunDevObj(UINode):
+ def __init__(self, name, parent):
+ UINode.__init__(self, name, parent)