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: Karol Latecki <karol.latecki@intel.com>
Signed-off-by: Pawel Kaminski <pawelx.kaminski@intel.com>
Reviewed-on: https://review.gerrithub.io/406538
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Karol Latecki 2018-04-05 11:08:09 +02:00 committed by Jim Harris
parent fdd6dbc902
commit 5e5cc5ac9c
2 changed files with 234 additions and 1 deletions

View File

@ -477,3 +477,191 @@ class UILvsObj(UINode):
free = "=".join(["Free", free]) free = "=".join(["Free", free])
info = ", ".join([str(size), str(free)]) info = ", ".join([str(size), str(free)])
return info, True 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)

View File

@ -1,4 +1,4 @@
from .ui_node import UINode, UIBdevs, UILvolStores from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts
import rpc.client import rpc.client
import rpc import rpc
@ -11,12 +11,14 @@ class UIRoot(UINode):
UINode.__init__(self, "/", shell=shell) UINode.__init__(self, "/", shell=shell)
self.current_bdevs = [] self.current_bdevs = []
self.current_lvol_stores = [] self.current_lvol_stores = []
self.current_vhost_ctrls = []
self.set_rpc_target(s) self.set_rpc_target(s)
def refresh(self): def refresh(self):
self._children = set([]) self._children = set([])
UIBdevs(self) UIBdevs(self)
UILvolStores(self) UILvolStores(self)
UIVhosts(self)
def set_rpc_target(self, s): def set_rpc_target(self, s):
self.client = rpc.client.JSONRPCClient(s) self.client = rpc.client.JSONRPCClient(s)
@ -121,6 +123,37 @@ class UIRoot(UINode):
response = rpc.bdev.construct_rbd_bdev(self.client, **kwargs) response = rpc.bdev.construct_rbd_bdev(self.client, **kwargs)
return response 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): class Bdev(object):
def __init__(self, bdev_info): def __init__(self, bdev_info):
@ -144,3 +177,15 @@ class LvolStore(object):
""" """
for i in lvs_info.keys(): for i in lvs_info.keys():
setattr(self, i, lvs_info[i]) 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])