Commit 5e5cc5ac authored by Karol Latecki's avatar Karol Latecki Committed by Jim Harris
Browse files

spdkcli: add basic vhost management



Adding:
- listing current vhost scsi and blk configuration
- add / remove scsi and blk controllers
- modify scsi targets and luns
- set controller coalescing

Change-Id: If00d820d03731f1110f665b14258617d917b9bfd
Signed-off-by: default avatarKarol Latecki <karol.latecki@intel.com>
Signed-off-by: default avatarPawel Kaminski <pawelx.kaminski@intel.com>
Reviewed-on: https://review.gerrithub.io/406538


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
parent fdd6dbc9
Loading
Loading
Loading
Loading
+188 −0
Original line number Diff line number Diff line
@@ -477,3 +477,191 @@ class UILvsObj(UINode):
        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.
        """
        ret_name = self.get_root().create_vhost_blk_controller(ctrlr=name,
                                                               dev_name=bdev,
                                                               cpumask=cpumask,
                                                               readonly=bool(readonly))
        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.
        """
        ret_name = self.get_root().create_vhost_scsi_controller(ctrlr=name,
                                                                cpumask=cpumask)
        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)
        self.get_root().set_vhost_controller_coalescing(ctrlr=self.ctrlr.ctrlr,
                                                        delay_base_us=delay_base_us,
                                                        iops_threshold=iops_threshold)


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.
        """
        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

        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.
        """

        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
        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(filter(None, [self.ctrlr.socket, ro]))
        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)
+46 −1
Original line number Diff line number Diff line
from .ui_node import UINode, UIBdevs, UILvolStores
from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts
import rpc.client
import rpc

@@ -11,12 +11,14 @@ class UIRoot(UINode):
        UINode.__init__(self, "/", shell=shell)
        self.current_bdevs = []
        self.current_lvol_stores = []
        self.current_vhost_ctrls = []
        self.set_rpc_target(s)

    def refresh(self):
        self._children = set([])
        UIBdevs(self)
        UILvolStores(self)
        UIVhosts(self)

    def set_rpc_target(self, s):
        self.client = rpc.client.JSONRPCClient(s)
@@ -121,6 +123,37 @@ class UIRoot(UINode):
        response = rpc.bdev.construct_rbd_bdev(self.client, **kwargs)
        return response

    def list_vhost_ctrls(self):
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def get_vhost_ctrlrs(self, ctrlr_type):
        for ctrlr in filter(lambda x: ctrlr_type in x["backend_specific"].keys(),
                            self.current_vhost_ctrls):
            yield VhostCtrlr(ctrlr)

    def remove_vhost_controller(self, **kwargs):
        rpc.vhost.remove_vhost_controller(self.client, **kwargs)
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def create_vhost_scsi_controller(self, **kwargs):
        rpc.vhost.construct_vhost_scsi_controller(self.client, **kwargs)
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def create_vhost_blk_controller(self, **kwargs):
        rpc.vhost.construct_vhost_blk_controller(self.client, **kwargs)
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def remove_vhost_scsi_target(self, **kwargs):
        rpc.vhost.remove_vhost_scsi_target(self.client, **kwargs)
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def add_vhost_scsi_lun(self, **kwargs):
        rpc.vhost.add_vhost_scsi_lun(self.client, **kwargs)
        self.current_vhost_ctrls = rpc.vhost.get_vhost_controllers(self.client)

    def set_vhost_controller_coalescing(self, **kwargs):
        rpc.vhost.set_vhost_controller_coalescing(self.client, **kwargs)


class Bdev(object):
    def __init__(self, bdev_info):
@@ -144,3 +177,15 @@ class LvolStore(object):
        """
        for i in lvs_info.keys():
            setattr(self, i, lvs_info[i])


class VhostCtrlr(object):
    def __init__(self, ctrlr_info):
        """
        All class attributes are set based on what information is received
        from get_vhost_controllers RPC call.
        # TODO: Document in docstring parameters which describe bdevs.
        # TODO: Possible improvement: JSON schema might be used here in future
        """
        for i in ctrlr_info.keys():
            setattr(self, i, ctrlr_info[i])