spdkcli: Add nvmf support
Add create/delete/get methods from nvmf subsystem to spdkcli. Change-Id: Id1f4e539d14746c4d6108bb58df921c301d47e96 Signed-off-by: Pawel Kaminski <pawelx.kaminski@intel.com> Reviewed-on: https://review.gerrithub.io/423425 Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Paweł Niedźwiecki <pawelx.niedzwiecki@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
parent
c7917f2252
commit
b6e130e98f
302
scripts/spdkcli/ui_node_nvmf.py
Normal file
302
scripts/spdkcli/ui_node_nvmf.py
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
from rpc.client import JSONRPCException
|
||||||
|
from .ui_node import UINode
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMf(UINode):
|
||||||
|
def __init__(self, parent):
|
||||||
|
UINode.__init__(self, "nvmf", parent)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
UINVMfSubsystems(self)
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystems(UINode):
|
||||||
|
def __init__(self, parent):
|
||||||
|
UINode.__init__(self, "subsystem", parent)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
for subsystem in self.get_root().get_nvmf_subsystems():
|
||||||
|
UINVMfSubsystem(subsystem, self)
|
||||||
|
|
||||||
|
def ui_command_create(self, nqn, serial_number=None,
|
||||||
|
max_namespaces=None, allow_any_host="false"):
|
||||||
|
"""Create subsystem with given parameteres.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
nqn - Target nqn(ASCII).
|
||||||
|
serial_number - Example: 'SPDK00000000000001'.
|
||||||
|
max_namespaces - Optional parameter. Maximum number of namespaces allowed to added during
|
||||||
|
active connection
|
||||||
|
allow_any_host - Optional parameter. Allow any host to connect (don't enforce host NQN
|
||||||
|
whitelist)
|
||||||
|
"""
|
||||||
|
allow_any_host = self.ui_eval_param(allow_any_host, "bool", False)
|
||||||
|
max_namespaces = self.ui_eval_param(max_namespaces, "number", 0)
|
||||||
|
try:
|
||||||
|
self.get_root().create_nvmf_subsystem(nqn=nqn, serial_number=serial_number,
|
||||||
|
allow_any_host=allow_any_host,
|
||||||
|
max_namespaces=max_namespaces)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def ui_command_delete(self, subsystem_nqn):
|
||||||
|
"""Delete subsystem with given nqn.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
nqn_subsystem - Name of susbsytem to delete
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.get_root().delete_nvmf_subsystem(nqn=subsystem_nqn)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
return "Subsystems: %s" % len(self.children), None
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystem(UINode):
|
||||||
|
def __init__(self, subsystem, parent):
|
||||||
|
UINode.__init__(self, subsystem.nqn, parent)
|
||||||
|
self.subsystem = subsystem
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
UINVMfSubsystemListeners(self.subsystem.listen_addresses, self)
|
||||||
|
UINVMfSubsystemHosts(self.subsystem.hosts, self)
|
||||||
|
if hasattr(self.subsystem, 'namespaces'):
|
||||||
|
UINVMfSubsystemNamespaces(self.subsystem.namespaces, self)
|
||||||
|
|
||||||
|
def refresh_node(self):
|
||||||
|
for subsystem in self.get_root().get_nvmf_subsystems():
|
||||||
|
if subsystem.nqn == self.subsystem.nqn:
|
||||||
|
self.subsystem = subsystem
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def ui_command_show_details(self):
|
||||||
|
self.shell.log.info(json.dumps(vars(self.lvs), indent=2))
|
||||||
|
|
||||||
|
def ui_command_allow_any_host(self, disable="false"):
|
||||||
|
"""Disable or or enable allow_any_host flag.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
disable - Optional parameter. If false then enable, if true disable
|
||||||
|
"""
|
||||||
|
disable = self.ui_eval_param(disable, "bool", None)
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_allow_any_host(
|
||||||
|
nqn=self.subsystem.nqn, disable=disable)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
sn = None
|
||||||
|
if hasattr(self.subsystem, 'serial_number'):
|
||||||
|
sn = "sn=%s" % self.subsystem.serial_number
|
||||||
|
st = None
|
||||||
|
if hasattr(self.subsystem, 'subtype'):
|
||||||
|
st = "st=%s" % self.subsystem.subtype
|
||||||
|
allow_any_host = None
|
||||||
|
if self.subsystem.allow_any_host:
|
||||||
|
allow_any_host = "Allow any host"
|
||||||
|
info = ", ".join(filter(None, [sn, st, allow_any_host]))
|
||||||
|
return info, None
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemListeners(UINode):
|
||||||
|
def __init__(self, listen_addresses, parent):
|
||||||
|
UINode.__init__(self, "listen_addresses", parent)
|
||||||
|
self.listen_addresses = listen_addresses
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
for address in self.listen_addresses:
|
||||||
|
UINVMfSubsystemListener(address, self)
|
||||||
|
|
||||||
|
def refresh_node(self):
|
||||||
|
for subsystem in self.get_root().get_nvmf_subsystems():
|
||||||
|
if subsystem.nqn == self.parent.subsystem.nqn:
|
||||||
|
self.listen_addresses = subsystem.listen_addresses
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def ui_command_create(self, trtype, traddr, trsvcid, adrfam):
|
||||||
|
"""Create address listener for subsystem.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
trtype - NVMe-oF transport type: e.g., rdma.
|
||||||
|
traddr - NVMe-oF transport address: e.g., an ip address.
|
||||||
|
trsvcid - NVMe-oF transport service id: e.g., a port number.
|
||||||
|
adrfam - NVMe-oF transport adrfam: e.g., ipv4, ipv6, ib, fc.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_add_listener(
|
||||||
|
nqn=self.parent.subsystem.nqn, trtype=trtype, traddr=traddr,
|
||||||
|
trsvcid=trsvcid, adrfam=adrfam)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def ui_command_delete(self, trtype, traddr, trsvcid, adrfam=None):
|
||||||
|
"""Remove address listener for subsystem.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
trtype - Transport type (RDMA)
|
||||||
|
traddr - NVMe-oF transport address: e.g., an ip address.
|
||||||
|
trsvcid - NVMe-oF transport service id: e.g., a port number.
|
||||||
|
adrfam - Optional argument. Address family ("IPv4", "IPv6", "IB" or "FC").
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_remove_listener(
|
||||||
|
nqn=self.parent.subsystem.nqn, trtype=trtype,
|
||||||
|
traddr=traddr, trsvcid=trsvcid, adrfam=adrfam)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
return "Addresses: %s" % len(self.listen_addresses), None
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemListener(UINode):
|
||||||
|
def __init__(self, address, parent):
|
||||||
|
UINode.__init__(self, "%s:%s" % (address['traddr'], address['trsvcid']),
|
||||||
|
parent)
|
||||||
|
self.address = address
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
return "%s" % self.address['trtype'], True
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemHosts(UINode):
|
||||||
|
def __init__(self, hosts, parent):
|
||||||
|
UINode.__init__(self, "hosts", parent)
|
||||||
|
self.hosts = hosts
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
for host in self.hosts:
|
||||||
|
UINVMfSubsystemHost(host, self)
|
||||||
|
|
||||||
|
def refresh_node(self):
|
||||||
|
for subsystem in self.get_root().get_nvmf_subsystems():
|
||||||
|
if subsystem.nqn == self.parent.subsystem.nqn:
|
||||||
|
self.hosts = subsystem.hosts
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def ui_command_create(self, host):
|
||||||
|
"""Add a host NQN to the whitelist of allowed hosts.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host: Host NQN to add to the list of allowed host NQNs
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_add_host(
|
||||||
|
nqn=self.parent.subsystem.nqn, host=host)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def ui_command_delete(self, host):
|
||||||
|
"""Delete host from subsystem.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
host - NQN of host to remove.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_remove_host(
|
||||||
|
nqn=self.parent.subsystem.nqn, host=host)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
return "Hosts: %s" % len(self.hosts), None
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemHost(UINode):
|
||||||
|
def __init__(self, host, parent):
|
||||||
|
UINode.__init__(self, "%s" % host['nqn'], parent)
|
||||||
|
self.host = host
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemNamespaces(UINode):
|
||||||
|
def __init__(self, namespaces, parent):
|
||||||
|
UINode.__init__(self, "namespaces", parent)
|
||||||
|
self.namespaces = namespaces
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
for namespace in self.namespaces:
|
||||||
|
UINVMfSubsystemNamespace(namespace, self)
|
||||||
|
|
||||||
|
def refresh_node(self):
|
||||||
|
for subsystem in self.get_root().get_nvmf_subsystems():
|
||||||
|
if subsystem.nqn == self.parent.subsystem.nqn:
|
||||||
|
self.namespaces = subsystem.namespaces
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def ui_command_create(self, bdev_name, nsid=None,
|
||||||
|
nguid=None, eui64=None, uuid=None):
|
||||||
|
"""Add a namespace to a subsystem.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bdev_name: Name of bdev to expose as a namespace.
|
||||||
|
Optional args:
|
||||||
|
nsid: Namespace ID.
|
||||||
|
nguid: 16-byte namespace globally unique identifier in hexadecimal.
|
||||||
|
eui64: 8-byte namespace EUI-64 in hexadecimal (e.g. "ABCDEF0123456789").
|
||||||
|
uuid: Namespace UUID.
|
||||||
|
"""
|
||||||
|
nsid = self.ui_eval_param(nsid, "number", None)
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_add_ns(
|
||||||
|
nqn=self.parent.subsystem.nqn, bdev_name=bdev_name,
|
||||||
|
nsid=nsid, nguid=nguid, eui64=eui64, uuid=uuid)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def ui_command_delete(self, nsid):
|
||||||
|
"""Delete namespace from subsystem.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
nsid - Id of namespace to remove.
|
||||||
|
"""
|
||||||
|
nsid = self.ui_eval_param(nsid, "number", None)
|
||||||
|
try:
|
||||||
|
self.get_root().nvmf_subsystem_remove_ns(
|
||||||
|
nqn=self.parent.subsystem.nqn, nsid=nsid)
|
||||||
|
except JSONRPCException as e:
|
||||||
|
self.shell.log.error(e.message)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh_node()
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
return "Namespaces: %s" % len(self.namespaces), None
|
||||||
|
|
||||||
|
|
||||||
|
class UINVMfSubsystemNamespace(UINode):
|
||||||
|
def __init__(self, namespace, parent):
|
||||||
|
UINode.__init__(self, namespace['bdev_name'], parent)
|
||||||
|
self.namespace = namespace
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
info = ", ".join([str(self.namespace['uuid']), self.namespace['name'],
|
||||||
|
str(self.namespace['nsid'])])
|
||||||
|
return info, None
|
@ -1,4 +1,5 @@
|
|||||||
from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts
|
from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts
|
||||||
|
from .ui_node_nvmf import UINVMf
|
||||||
import rpc.client
|
import rpc.client
|
||||||
import rpc
|
import rpc
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
@ -13,6 +14,7 @@ class UIRoot(UINode):
|
|||||||
self.current_bdevs = []
|
self.current_bdevs = []
|
||||||
self.current_lvol_stores = []
|
self.current_lvol_stores = []
|
||||||
self.current_vhost_ctrls = []
|
self.current_vhost_ctrls = []
|
||||||
|
self.current_nvmf_subsystems = []
|
||||||
self.set_rpc_target(s)
|
self.set_rpc_target(s)
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
self.is_init = self.check_init()
|
self.is_init = self.check_init()
|
||||||
@ -34,6 +36,7 @@ class UIRoot(UINode):
|
|||||||
UIBdevs(self)
|
UIBdevs(self)
|
||||||
UILvolStores(self)
|
UILvolStores(self)
|
||||||
UIVhosts(self)
|
UIVhosts(self)
|
||||||
|
UINVMf(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)
|
||||||
@ -248,6 +251,56 @@ class UIRoot(UINode):
|
|||||||
def set_vhost_controller_coalescing(self, **kwargs):
|
def set_vhost_controller_coalescing(self, **kwargs):
|
||||||
rpc.vhost.set_vhost_controller_coalescing(self.client, **kwargs)
|
rpc.vhost.set_vhost_controller_coalescing(self.client, **kwargs)
|
||||||
|
|
||||||
|
def list_nvmf_subsystems(self):
|
||||||
|
if self.is_init:
|
||||||
|
self.current_nvmf_subsystems = rpc.nvmf.get_nvmf_subsystems(self.client)
|
||||||
|
|
||||||
|
def get_nvmf_subsystems(self):
|
||||||
|
if self.is_init:
|
||||||
|
self.list_nvmf_subsystems()
|
||||||
|
for subsystem in self.current_nvmf_subsystems:
|
||||||
|
yield NvmfSubsystem(subsystem)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def create_nvmf_subsystem(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_create(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def delete_nvmf_subsystem(self, **kwargs):
|
||||||
|
rpc.nvmf.delete_nvmf_subsystem(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_add_listener(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_add_listener(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_remove_listener(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_remove_listener(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_add_host(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_add_host(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_remove_host(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_remove_host(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_allow_any_host(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_allow_any_host(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_add_ns(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_add_ns(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_remove_ns(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_remove_ns(self.client, **kwargs)
|
||||||
|
|
||||||
|
@verbose
|
||||||
|
def nvmf_subsystem_allow_any_host(self, **kwargs):
|
||||||
|
rpc.nvmf.nvmf_subsystem_allow_any_host(self.client, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Bdev(object):
|
class Bdev(object):
|
||||||
def __init__(self, bdev_info):
|
def __init__(self, bdev_info):
|
||||||
@ -283,3 +336,15 @@ class VhostCtrlr(object):
|
|||||||
"""
|
"""
|
||||||
for i in list(ctrlr_info.keys()):
|
for i in list(ctrlr_info.keys()):
|
||||||
setattr(self, i, ctrlr_info[i])
|
setattr(self, i, ctrlr_info[i])
|
||||||
|
|
||||||
|
|
||||||
|
class NvmfSubsystem(object):
|
||||||
|
def __init__(self, subsystem_info):
|
||||||
|
"""
|
||||||
|
All class attributes are set based on what information is received
|
||||||
|
from get_nvmf_subsystem RPC call.
|
||||||
|
# TODO: Document in docstring parameters which describe bdevs.
|
||||||
|
# TODO: Possible improvement: JSON schema might be used here in future
|
||||||
|
"""
|
||||||
|
for i in subsystem_info.keys():
|
||||||
|
setattr(self, i, subsystem_info[i])
|
||||||
|
@ -27,6 +27,11 @@ o- / ...........................................................................
|
|||||||
| o- virtioscsi_disk .................................................................................................. [Bdevs: 0]
|
| o- virtioscsi_disk .................................................................................................. [Bdevs: 0]
|
||||||
o- lvol_stores .................................................................................................. [Lvol stores: 1]
|
o- lvol_stores .................................................................................................. [Lvol stores: 1]
|
||||||
| o- lvs ................................................................................................ [Size=$(FP)M, Free=$(FP)M]
|
| o- lvs ................................................................................................ [Size=$(FP)M, Free=$(FP)M]
|
||||||
|
o- nvmf .................................................................................................................... [...]
|
||||||
|
| o- subsystem ................................................................................................... [Subsystems: 1]
|
||||||
|
| o- nqn.2014-08.org.nvmexpress.discovery ....................................................... [st=Discovery, Allow any host]
|
||||||
|
| o- hosts ........................................................................................................ [Hosts: 0]
|
||||||
|
| o- listen_addresses ......................................................................................... [Addresses: 0]
|
||||||
o- vhost ................................................................................................................... [...]
|
o- vhost ................................................................................................................... [...]
|
||||||
o- block ................................................................................................................. [...]
|
o- block ................................................................................................................. [...]
|
||||||
| o- vhost_blk1 $(S) [$(S)]
|
| o- vhost_blk1 $(S) [$(S)]
|
||||||
|
Loading…
Reference in New Issue
Block a user