spdkcli: initial version with bdev management
Initial version for SPDKCli Possible basic management of: - Bdevs: malloc, nvme, aio, lvol create / delete operations. - Lvol stores: create / delete operations. Adding dependency to pkgdep.sh. Change-Id: I1a03d7660dad0335e25734b8ffb90592a5b337c2 Signed-off-by: Karol Latecki <karol.latecki@intel.com> Reviewed-on: https://review.gerrithub.io/405039 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
parent
4ecb2e1d33
commit
83795a1600
@ -804,6 +804,7 @@ INPUT = ../include/spdk \
|
|||||||
nvmf.md \
|
nvmf.md \
|
||||||
nvmf_tgt_pg.md \
|
nvmf_tgt_pg.md \
|
||||||
peer_2_peer.md \
|
peer_2_peer.md \
|
||||||
|
spdkcli.md \
|
||||||
ssd_internals.md \
|
ssd_internals.md \
|
||||||
userspace.md \
|
userspace.md \
|
||||||
vagrant.md \
|
vagrant.md \
|
||||||
|
@ -53,6 +53,10 @@
|
|||||||
|
|
||||||
- @ref nvme-cli
|
- @ref nvme-cli
|
||||||
|
|
||||||
|
# Experimental Tools {#experimental_tools}
|
||||||
|
|
||||||
|
- @ref spdkcli
|
||||||
|
|
||||||
# Performance Reports {#performancereports}
|
# Performance Reports {#performancereports}
|
||||||
|
|
||||||
- [SPDK 17.07 vhost-scsi Performance Report](https://ci.spdk.io/download/performance-reports/SPDK17_07_vhost_scsi_performance_report.pdf)
|
- [SPDK 17.07 vhost-scsi Performance Report](https://ci.spdk.io/download/performance-reports/SPDK17_07_vhost_scsi_performance_report.pdf)
|
||||||
|
61
doc/spdkcli.md
Normal file
61
doc/spdkcli.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# SPDK CLI {#spdkcli}
|
||||||
|
|
||||||
|
Spdkcli is a command-line management application for SPDK.
|
||||||
|
Spdkcli has support for a limited number of applications and bdev modules,
|
||||||
|
and should be considered experimental for the v18.04 release.
|
||||||
|
This experimental version was added for v18.04 to get early feedback
|
||||||
|
that can be incorporated as spdkcli becomes more fully-featured
|
||||||
|
for the next SPDK release.
|
||||||
|
|
||||||
|
### Install needed dependencies
|
||||||
|
|
||||||
|
All dependencies should be handled by scripts/pkgdep.sh script.
|
||||||
|
Package dependencies at the moment include:
|
||||||
|
- configshell
|
||||||
|
|
||||||
|
### Run SPDK application instance
|
||||||
|
|
||||||
|
~~~{.sh}
|
||||||
|
./scripts/setup.sh
|
||||||
|
./app/vhost/vhost -c vhost.conf
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### Run SPDK CLI
|
||||||
|
|
||||||
|
Spdkcli should be run with the same priviliges as SPDK application.
|
||||||
|
In order to use SPDK CLI in interactive mode please use:
|
||||||
|
~~~{.sh}
|
||||||
|
scripts/spdkcli.py
|
||||||
|
~~~
|
||||||
|
Use "help" command to get a list of available commands for each tree node.
|
||||||
|
|
||||||
|
It is also possible to use SPDK CLI to run just a single command,
|
||||||
|
just use the command as an argument to the application.
|
||||||
|
For example, to view current configuration and immediately exit:
|
||||||
|
~~~{.sh}
|
||||||
|
scripts/spdkcli.py ls
|
||||||
|
~~~
|
||||||
|
|
||||||
|
### Optional - create Python virtual environment
|
||||||
|
|
||||||
|
You can use Python virtual environment if you don't want to litter your
|
||||||
|
system Python installation.
|
||||||
|
|
||||||
|
First create the virtual environment:
|
||||||
|
~~~{.sh}
|
||||||
|
cd spdk
|
||||||
|
mkdir venv
|
||||||
|
virtualenv-3 ./venv
|
||||||
|
source ./venv/bin/activate
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Then install the dependencies using pip. That way depedencies will be
|
||||||
|
installed only inside the virtual environment.
|
||||||
|
~~~{.sh}
|
||||||
|
(venv) pip install configshell-fb
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Tip: if you are using "sudo" instead of root account, it is suggested to do
|
||||||
|
"sudo -s" before activating the environment. This is because venv might not work
|
||||||
|
correctly when calling spdkcli with sudo, like "sudo python spdkcli.py" -
|
||||||
|
some environment variables might not be passed and you will experience errors.
|
@ -20,6 +20,8 @@ if [ -s /etc/redhat-release ]; then
|
|||||||
yum install -y doxygen mscgen graphviz
|
yum install -y doxygen mscgen graphviz
|
||||||
# Additional dependencies for building pmem based backends
|
# Additional dependencies for building pmem based backends
|
||||||
yum install -y libpmemblk-devel || true
|
yum install -y libpmemblk-devel || true
|
||||||
|
# Additional dependencies for SPDK CLI
|
||||||
|
yum install -y python-configshell
|
||||||
elif [ -f /etc/debian_version ]; then
|
elif [ -f /etc/debian_version ]; then
|
||||||
# Includes Ubuntu, Debian
|
# Includes Ubuntu, Debian
|
||||||
apt-get install -y gcc g++ make libcunit1-dev libaio-dev libssl-dev \
|
apt-get install -y gcc g++ make libcunit1-dev libaio-dev libssl-dev \
|
||||||
@ -30,6 +32,8 @@ elif [ -f /etc/debian_version ]; then
|
|||||||
apt-get install -y libnuma-dev
|
apt-get install -y libnuma-dev
|
||||||
# Additional dependencies for building docs
|
# Additional dependencies for building docs
|
||||||
apt-get install -y doxygen mscgen graphviz
|
apt-get install -y doxygen mscgen graphviz
|
||||||
|
# Additional dependencies for SPDK CLI
|
||||||
|
apt-get install -y "python-configshell*"
|
||||||
elif [ $SYSTEM = "FreeBSD" ] ; then
|
elif [ $SYSTEM = "FreeBSD" ] ; then
|
||||||
pkg install gmake cunit openssl git devel/astyle bash devel/pep8 \
|
pkg install gmake cunit openssl git devel/astyle bash devel/pep8 \
|
||||||
python misc/e2fsprogs-libuuid sysutils/sg3_utils
|
python misc/e2fsprogs-libuuid sysutils/sg3_utils
|
||||||
|
38
scripts/spdkcli.py
Executable file
38
scripts/spdkcli.py
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
from os import getuid
|
||||||
|
from configshell_fb import ConfigShell
|
||||||
|
from spdkcli import UIRoot
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Start SPDK CLI
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
shell = ConfigShell("~/.scripts")
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="SPDK command line interface")
|
||||||
|
parser.add_argument("-s", dest="socket", help="RPC socket path", default="/var/tmp/spdk.sock")
|
||||||
|
parser.add_argument("commands", metavar="command", type=str, nargs="*", default="",
|
||||||
|
help="commands to execute by SPDKCli as one-line command")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
root_node = UIRoot(args.socket, shell)
|
||||||
|
try:
|
||||||
|
root_node.refresh()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(args.commands) > 0:
|
||||||
|
shell.run_cmdline(" ".join(args.commands))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
shell.con.display("SPDK CLI v0.1")
|
||||||
|
shell.con.display("")
|
||||||
|
shell.run_interactive()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
1
scripts/spdkcli/__init__.py
Normal file
1
scripts/spdkcli/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .ui_root import UIRoot
|
297
scripts/spdkcli/ui_node.py
Normal file
297
scripts/spdkcli/ui_node.py
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
from configshell_fb import ConfigNode, ExecutionError
|
||||||
|
from uuid import UUID
|
||||||
|
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)
|
||||||
|
|
||||||
|
def ui_command_delete(self, name):
|
||||||
|
"""
|
||||||
|
Deletes bdev from configuration.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
name - Is a unique identifier of the bdev to be deleted - UUID number or name alias.
|
||||||
|
"""
|
||||||
|
self.get_root().delete_bdev(name=name)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.get_root().create_lvol_store(lvs_name=name, bdev_name=bdev_name, cluster_sz=cluster_size)
|
||||||
|
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_delete(self, name):
|
||||||
|
"""
|
||||||
|
Deletes bdev from configuration.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
name - Is a unique identifier of the bdev to be deleted - UUID number or name alias.
|
||||||
|
"""
|
||||||
|
self.get_root().delete_bdev(name=name)
|
||||||
|
self.get_root().refresh()
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
ret_name = self.get_root().create_malloc_bdev(total_size=size,
|
||||||
|
block_size=block_size,
|
||||||
|
name=name, uuid=uuid)
|
||||||
|
self.shell.log.info(ret_name)
|
||||||
|
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)
|
||||||
|
|
||||||
|
ret_name = self.get_root().create_aio_bdev(name=name,
|
||||||
|
block_size=int(block_size),
|
||||||
|
filename=filename)
|
||||||
|
self.shell.log.info(ret_name)
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
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.")
|
||||||
|
|
||||||
|
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)
|
||||||
|
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(filter(None, [alias, size, in_use]))
|
||||||
|
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
|
96
scripts/spdkcli/ui_root.py
Normal file
96
scripts/spdkcli/ui_root.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
from .ui_node import UINode, UIBdevs, UILvolStores
|
||||||
|
import rpc.client
|
||||||
|
import rpc
|
||||||
|
from argparse import Namespace as an
|
||||||
|
|
||||||
|
|
||||||
|
class UIRoot(UINode):
|
||||||
|
"""
|
||||||
|
Root node for CLI menu tree structure. Refreshes running config on startup.
|
||||||
|
"""
|
||||||
|
def __init__(self, s, shell):
|
||||||
|
UINode.__init__(self, "/", shell=shell)
|
||||||
|
self.current_bdevs = []
|
||||||
|
self.current_lvol_stores = []
|
||||||
|
self.set_rpc_target(s)
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self._children = set([])
|
||||||
|
UIBdevs(self)
|
||||||
|
UILvolStores(self)
|
||||||
|
|
||||||
|
def set_rpc_target(self, s):
|
||||||
|
self.client = rpc.client.JSONRPCClient(s)
|
||||||
|
|
||||||
|
def print_array(self, a):
|
||||||
|
return " ".join(a)
|
||||||
|
|
||||||
|
def get_bdevs(self, bdev_type):
|
||||||
|
self.current_bdevs = rpc.bdev.get_bdevs(self.client, an(name=""))
|
||||||
|
# Following replace needs to be done in order for some of the bdev
|
||||||
|
# listings to work.
|
||||||
|
# For example logical volumes: listing in menu is "Logical_Volume"
|
||||||
|
# (cannot have space), but the product name in SPDK is "Logical Volume"
|
||||||
|
bdev_type = bdev_type.replace("_", " ")
|
||||||
|
for bdev in filter(lambda x: bdev_type in x["product_name"],
|
||||||
|
self.current_bdevs):
|
||||||
|
test = Bdev(bdev)
|
||||||
|
yield test
|
||||||
|
|
||||||
|
def delete_bdev(self, name):
|
||||||
|
rpc.bdev.delete_bdev(self.client, an(bdev_name=name))
|
||||||
|
|
||||||
|
def create_malloc_bdev(self, **kwargs):
|
||||||
|
response = rpc.bdev.construct_malloc_bdev(self.client, an(**kwargs))
|
||||||
|
return self.print_array(response)
|
||||||
|
|
||||||
|
def create_aio_bdev(self, **kwargs):
|
||||||
|
response = rpc.bdev.construct_aio_bdev(self.client, an(**kwargs))
|
||||||
|
return self.print_array(response)
|
||||||
|
|
||||||
|
def create_lvol_bdev(self, **kwargs):
|
||||||
|
response = rpc.lvol.construct_lvol_bdev(self.client, **kwargs)
|
||||||
|
return self.print_array(response)
|
||||||
|
|
||||||
|
def create_nvme_bdev(self, **kwargs):
|
||||||
|
response = rpc.bdev.construct_nvme_bdev(self.client, an(**kwargs))
|
||||||
|
return self.print_array(response)
|
||||||
|
|
||||||
|
def get_lvol_stores(self):
|
||||||
|
self.current_lvol_stores = rpc.lvol.get_lvol_stores(self.client)
|
||||||
|
for lvs in self.current_lvol_stores:
|
||||||
|
yield LvolStore(lvs)
|
||||||
|
|
||||||
|
def create_lvol_store(self, **kwargs):
|
||||||
|
response = rpc.lvol.construct_lvol_store(self.client, **kwargs)
|
||||||
|
new_lvs = rpc.lvol.get_lvol_stores(self.client,
|
||||||
|
self.print_array(response),
|
||||||
|
lvs_name=None)
|
||||||
|
return new_lvs[0]["name"]
|
||||||
|
|
||||||
|
def delete_lvol_store(self, **kwargs):
|
||||||
|
rpc.lvol.destroy_lvol_store(self.client, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Bdev(object):
|
||||||
|
def __init__(self, bdev_info):
|
||||||
|
"""
|
||||||
|
All class attributes are set based on what information is received
|
||||||
|
from get_bdevs RPC call.
|
||||||
|
# TODO: Document in docstring parameters which describe bdevs.
|
||||||
|
# TODO: Possible improvement: JSON schema might be used here in future
|
||||||
|
"""
|
||||||
|
for i in bdev_info.keys():
|
||||||
|
setattr(self, i, bdev_info[i])
|
||||||
|
|
||||||
|
|
||||||
|
class LvolStore(object):
|
||||||
|
def __init__(self, lvs_info):
|
||||||
|
"""
|
||||||
|
All class attributes are set based on what information is received
|
||||||
|
from get_bdevs RPC call.
|
||||||
|
# TODO: Document in docstring parameters which describe bdevs.
|
||||||
|
# TODO: Possible improvement: JSON schema might be used here in future
|
||||||
|
"""
|
||||||
|
for i in lvs_info.keys():
|
||||||
|
setattr(self, i, lvs_info[i])
|
Loading…
Reference in New Issue
Block a user