From 3d0488d28a37aff396ce205e0be6250588e3990f Mon Sep 17 00:00:00 2001 From: Pawel Kaminski Date: Tue, 4 Sep 2018 22:41:29 -0400 Subject: [PATCH] spdkcli: Add iscsi subsystem. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add create/delete methods from iscsi subsystem to spdkcli. Change-Id: I950b3f29720fd5f09e4144d139e6d0e5885c69c8 Signed-off-by: Pawel Kaminski Reviewed-on: https://review.gerrithub.io/424607 Tested-by: SPDK CI Jenkins Chandler-Test-Pool: SPDK Automated Test System Reviewed-by: Paweł Niedźwiecki Reviewed-by: Karol Latecki Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- scripts/spdkcli/ui_node_iscsi.py | 635 ++++++++++++++++++ scripts/spdkcli/ui_root.py | 116 ++++ .../match_files/spdkcli_vhost.test.match | 24 + 3 files changed, 775 insertions(+) create mode 100644 scripts/spdkcli/ui_node_iscsi.py diff --git a/scripts/spdkcli/ui_node_iscsi.py b/scripts/spdkcli/ui_node_iscsi.py new file mode 100644 index 000000000..65592a75f --- /dev/null +++ b/scripts/spdkcli/ui_node_iscsi.py @@ -0,0 +1,635 @@ +from rpc.client import JSONRPCException +from .ui_node import UINode + + +class UIISCSI(UINode): + def __init__(self, parent): + UINode.__init__(self, "iscsi", parent) + self.refresh() + + def refresh(self): + self._children = set([]) + UIISCSIDevices(self) + UIPortalGroups(self) + UIInitiatorGroups(self) + UIISCSIConnections(self) + UIISCSIAuthGroups(self) + UIISCSIGlobalParams(self) + + +class UIISCSIGlobalParams(UINode): + def __init__(self, parent): + UINode.__init__(self, "global_params", parent) + self.refresh() + + def refresh(self): + self._children = set([]) + for param, val in self.get_root().get_iscsi_global_params().items(): + UIISCSIGlobalParam("%s: %s" % (param, val), self) + + def ui_command_set_auth(self, g=None, d=None, r=None, m=None): + """Set CHAP authentication for discovery service. + + Optional arguments: + g = chap_group: Authentication group ID for discovery session + d = disable_chap: CHAP for discovery session should be disabled + r = require_chap: CHAP for discovery session should be required + m = mutual_chap: CHAP for discovery session should be mutual + """ + chap_group = self.ui_eval_param(g, "number", None) + disable_chap = self.ui_eval_param(d, "bool", None) + require_chap = self.ui_eval_param(r, "bool", None) + mutual_chap = self.ui_eval_param(m, "bool", None) + try: + self.get_root().set_iscsi_discovery_auth( + chap_group=chap_group, disable_chap=disable_chap, + require_chap=require_chap, mutual_chap=mutual_chap) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.refresh() + + +class UIISCSIGlobalParam(UINode): + def __init__(self, param, parent): + UINode.__init__(self, param, parent) + + +class UIISCSIDevices(UINode): + def __init__(self, parent): + UINode.__init__(self, "target_nodes", parent) + self.refresh() + + def refresh(self): + self._children = set([]) + self.target_nodes = list(self.get_root().get_target_nodes()) + self.scsi_devices = list(self.get_root().get_scsi_devices()) + for device in self.scsi_devices: + for node in self.target_nodes: + if hasattr(device, "device_name") and node['name'] \ + == device.device_name: + UIISCSIDevice(device, node, self) + + def ui_command_create(self, name, alias_name, bdev_name_id_pairs, + pg_ig_mappings, queue_depth, g=None, d=None, r=None, + m=None, h=None, t=None): + """Create target node + + Positional args: + name: Target node name (ASCII) + alias_name: Target node alias name (ASCII) + bdev_name_id_pairs: List of bdev_name_id_pairs + pg_ig_mappings: List of pg_ig_mappings + queue_depth: Desired target queue depth + Optional args: + g = chap_group: Authentication group ID for this target node + d = disable_chap: CHAP authentication should be disabled for this target node + r = require_chap: CHAP authentication should be required for this target node + m = mutual_chap: CHAP authentication should be mutual/bidirectional + h = header_digest: Header Digest should be required for this target node + t = data_digest: Data Digest should be required for this target node + """ + luns = [] + print("bdev_name_id_pairs: %s" % bdev_name_id_pairs) + print("pg_ig_mappings: %s" % pg_ig_mappings) + for u in bdev_name_id_pairs.strip().split(" "): + bdev_name, lun_id = u.split(":") + luns.append({"bdev_name": bdev_name, "lun_id": int(lun_id)}) + pg_ig_maps = [] + for u in pg_ig_mappings.strip().split(" "): + pg, ig = u.split(":") + pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) + queue_depth = self.ui_eval_param(queue_depth, "number", None) + chap_group = self.ui_eval_param(g, "number", None) + disable_chap = self.ui_eval_param(d, "bool", None) + require_chap = self.ui_eval_param(r, "bool", None) + mutual_chap = self.ui_eval_param(m, "bool", None) + header_digest = self.ui_eval_param(h, "bool", None) + data_digest = self.ui_eval_param(t, "bool", None) + try: + self.get_root().construct_target_node( + name=name, alias_name=alias_name, luns=luns, + pg_ig_maps=pg_ig_maps, queue_depth=queue_depth, + chap_group=chap_group, disable_chap=disable_chap, + require_chap=require_chap, mutual_chap=mutual_chap, + header_digest=header_digest, data_digest=data_digest) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_delete(self, name=None): + """Delete a target node. If name is not specified delete all target nodes. + + Arguments: + name - Target node name. + """ + if name is None: + for device in self.devices: + try: + self.get_root().delete_target_node( + target_node_name=device.device_name) + except JSONRPCException as e: + self.shell.log.error(e.message) + else: + try: + self.get_root().delete_target_node(target_node_name=name) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.refresh() + + def ui_command_add_lun(self, name, bdev_name, lun_id=None): + """Add lun to the target node. + + Required args: + name: Target node name (ASCII) + bdev_name: bdev name + Positional args: + lun_id: LUN ID (integer >= 0) + """ + if lun_id: + lun_id = self.ui_eval_param(lun_id, "number", None) + try: + self.get_root().target_node_add_lun( + name=name, bdev_name=bdev_name, lun_id=lun_id) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.parent.refresh() + + def summary(self): + count = 0 + for device in self.scsi_devices: + for node in self.target_nodes: + if hasattr(device, "device_name") and node['name'] \ + == device.device_name: + count = count + 1 + return "Target nodes: %d" % count, None + + +class UIISCSIDevice(UINode): + def __init__(self, device, target, parent): + UINode.__init__(self, device.device_name, parent) + self.device = device + self.target = target + self.refresh() + + def ui_command_set_auth(self, g=None, d=None, r=None, m=None): + """Set CHAP authentication for the target node. + + Optionals args: + g = chap_group: Authentication group ID for this target node + d = disable_chap: CHAP authentication should be disabled for this target node + r = require_chap: CHAP authentication should be required for this target node + m = mutual_chap: CHAP authentication should be mutual/bidirectional + """ + chap_group = self.ui_eval_param(g, "number", None) + disable_chap = self.ui_eval_param(d, "bool", None) + require_chap = self.ui_eval_param(r, "bool", None) + mutual_chap = self.ui_eval_param(m, "bool", None) + try: + self.get_root().set_iscsi_target_node_auth( + name=self.device.device_name, chap_group=chap_group, + disable_chap=disable_chap, + require_chap=require_chap, mutual_chap=mutual_chap) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.parent.refresh() + + def ui_command_add_pg_ig_maps(self, pg_ig_mappings): + """Add PG-IG maps to the target node. + + Args: + pg_ig_maps: List of pg_ig_mappings, e.g. pg_tag:ig_tag pg_tag2:ig_tag2 + """ + pg_ig_maps = [] + for u in pg_ig_mappings.strip().split(" "): + pg, ig = u.split(":") + pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) + try: + self.get_root().add_pg_ig_maps( + pg_ig_maps=pg_ig_maps, name=self.device.device_name) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.parent.refresh() + + def ui_command_delete_pg_ig_maps(self, pg_ig_mappings): + """Add PG-IG maps to the target node. + + Args: + pg_ig_maps: List of pg_ig_mappings, e.g. pg_tag:ig_tag pg_tag2:ig_tag2 + """ + pg_ig_maps = [] + for u in pg_ig_mappings.strip().split(" "): + pg, ig = u.split(":") + pg_ig_maps.append({"pg_tag": int(pg), "ig_tag": int(ig)}) + try: + self.get_root().delete_pg_ig_maps( + pg_ig_maps=pg_ig_maps, name=self.device.device_name) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.parent.refresh() + + def refresh(self): + self._children = set([]) + UIISCSILuns(self.target['luns'], self) + UIISCSIPgIgMaps(self.target['pg_ig_maps'], self) + auths = {"disable_chap": self.target["disable_chap"], + "require_chap": self.target["require_chap"], + "mutual_chap": self.target["mutual_chap"], + "chap_group": self.target["chap_group"], + "data_digest": self.target["data_digest"]} + UIISCSIAuth(auths, self) + + def summary(self): + return "Id: %s, QueueDepth: %s" % (self.device.id, + self.target['queue_depth']), None + + +class UIISCSIAuth(UINode): + def __init__(self, auths, parent): + UINode.__init__(self, "auths", parent) + self.auths = auths + self.refresh() + + def summary(self): + return "disable_chap: %s, require_chap: %s, mutual_chap: %s, chap_group: %s" % ( + self.auths['disable_chap'], self.auths['require_chap'], + self.auths['mutual_chap'], self.auths['chap_group']), None + + +class UIISCSILuns(UINode): + def __init__(self, luns, parent): + UINode.__init__(self, "luns", parent) + self.luns = luns + self.refresh() + + def refresh(self): + self._children = set([]) + for lun in self.luns: + UIISCSILun(lun, self) + + def summary(self): + return "Luns: %d" % len(self.luns), None + + +class UIISCSILun(UINode): + def __init__(self, lun, parent): + UINode.__init__(self, "lun %s" % lun['lun_id'], parent) + self.lun = lun + self.refresh() + + def summary(self): + return "%s" % self.lun['bdev_name'], None + + +class UIISCSIPgIgMaps(UINode): + def __init__(self, pg_ig_maps, parent): + UINode.__init__(self, "pg_ig_maps", parent) + self.pg_ig_maps = pg_ig_maps + self.refresh() + + def refresh(self): + self._children = set([]) + for pg_ig in self.pg_ig_maps: + UIISCSIPgIg(pg_ig, self) + + def summary(self): + return "Pg_ig_maps: %d" % len(self.pg_ig_maps), None + + +class UIISCSIPgIg(UINode): + def __init__(self, pg_ig, parent): + UINode.__init__(self, "portal_group%s - initiator_group%s" % + (pg_ig['pg_tag'], pg_ig['ig_tag']), parent) + self.pg_ig = pg_ig + self.refresh() + + +class UIPortalGroups(UINode): + def __init__(self, parent): + UINode.__init__(self, "portal_groups", parent) + self.refresh() + + def ui_command_create(self, tag, portal_list): + """Add a portal group. + + Args: + portals: List of portals e.g. ip:port@cpumask ip2:port2 + tag: Portal group tag (unique, integer > 0) + """ + portals = [] + print("portal_list: %s" % portal_list) + for portal in portal_list.strip().split(" "): + host = portal + cpumask = None + if "@" in portal: + host, cpumask = portal.split("@") + host, port = host.rsplit(":", -1) + portals.append({'host': host, 'port': port}) + if cpumask: + portals[-1]['cpumask'] = cpumask + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().construct_portal_group(tag=tag, portals=portals) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_delete(self, tag): + """Delete a portal group with given tag (unique, integer > 0))""" + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().delete_portal_group(tag=tag) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def refresh(self): + self._children = set([]) + self.pgs = list(self.get_root().get_portal_groups()) + for pg in self.pgs: + UIPortalGroup(pg, self) + + def summary(self): + return "Portal groups: %d" % len(self.pgs), None + + +class UIPortalGroup(UINode): + def __init__(self, pg, parent): + UINode.__init__(self, "portal_group%s" % pg.tag, parent) + self.pg = pg + self.refresh() + + def refresh(self): + self._children = set([]) + for portal in self.pg.portals: + UIPortal(portal['host'], portal['port'], portal['cpumask'], self) + + def summary(self): + return "Portals: %d" % len(self.pg.portals), None + + +class UIPortal(UINode): + def __init__(self, host, port, cpumask, parent): + UINode.__init__(self, "host=%s, port=%s, cpumask=%s" % ( + host, port, cpumask), parent) + self.refresh() + + +class UIInitiatorGroups(UINode): + def __init__(self, parent): + UINode.__init__(self, "initiator_groups", parent) + self.refresh() + + def ui_command_create(self, tag, initiator_list, netmask_list): + """Add an initiator group. + + Args: + tag: Initiator group tag (unique, integer > 0) + initiators: List of initiator hostnames or IP addresses + separated with whitespaces, e.g. 127.0.0.1 192.168.200.100 + netmasks: List of initiator netmasks separated with whitespaces, + e.g. 255.255.0.0 255.248.0.0 + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().construct_initiator_group( + tag=tag, initiators=initiator_list.split(" "), + netmasks=netmask_list.split(" ")) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_delete(self, tag): + """Delete an initiator group. + + Args: + tag: Initiator group tag (unique, integer > 0) + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().delete_initiator_group(tag=tag) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_add_initiator(self, tag, initiators, netmasks): + """Add initiators to an existing initiator group. + + Args: + tag: Initiator group tag (unique, integer > 0) + initiators: List of initiator hostnames or IP addresses, + e.g. 127.0.0.1 192.168.200.100 + netmasks: List of initiator netmasks, + e.g. 255.255.0.0 255.248.0.0 + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().add_initiators_to_initiator_group( + tag=tag, initiators=initiators.split(" "), + netmasks=netmasks.split(" ")) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_delete_initiator(self, tag, initiators=None, netmasks=None): + """Delete initiators from an existing initiator group. + + Args: + tag: Initiator group tag (unique, integer > 0) + initiators: List of initiator hostnames or IP addresses, e.g. 127.0.0.1 192.168.200.100 + netmasks: List of initiator netmasks, e.g. 255.255.0.0 255.248.0.0 + """ + tag = self.ui_eval_param(tag, "number", None) + if initiators: + initiators = initiators.split(" ") + if netmasks: + netmasks = netmasks.split(" ") + try: + self.get_root().delete_initiators_from_initiator_group( + tag=tag, initiators=initiators, + netmasks=netmasks) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def refresh(self): + self._children = set([]) + self.igs = list(self.get_root().get_initiator_groups()) + for ig in self.igs: + UIInitiatorGroup(ig, self) + + def summary(self): + return "Initiator groups: %d" % len(self.igs), None + + +class UIInitiatorGroup(UINode): + def __init__(self, ig, parent): + UINode.__init__(self, "initiator_group%s" % ig.tag, parent) + self.ig = ig + self.refresh() + + def refresh(self): + self._children = set([]) + for initiator, netmask in zip(self.ig.initiators, self.ig.netmasks): + UIInitiator(initiator, netmask, self) + + def summary(self): + return "Initiators: %d" % len(self.ig.initiators), None + + +class UIInitiator(UINode): + def __init__(self, initiator, netmask, parent): + UINode.__init__(self, "hostname=%s, netmask=%s" % (initiator, netmask), parent) + self.refresh() + + +class UIISCSIConnections(UINode): + def __init__(self, parent): + UINode.__init__(self, "iscsi_connections", parent) + self.refresh() + + def refresh(self): + self._children = set([]) + self.iscsicons = list(self.get_root().get_iscsi_connections()) + for ic in self.iscsicons: + UIISCSIConnection(ic, self) + + def summary(self): + return "Connections: %d" % len(self.iscsicons), None + + +class UIISCSIConnection(UINode): + def __init__(self, ic, parent): + UINode.__init__(self, "%s" % ic['id'], parent) + self.ic = ic + self.refresh() + + def refresh(self): + self._children = set([]) + for key, val in self.ic.iteritems(): + if key == "id": + continue + UIISCSIConnectionDetails("%s: %s" % (key, val), self) + + +class UIISCSIConnectionDetails(UINode): + def __init__(self, info, parent): + UINode.__init__(self, "%s" % info, parent) + self.refresh() + + +class UIISCSIAuthGroups(UINode): + def __init__(self, parent): + UINode.__init__(self, "auth_groups", parent) + self.refresh() + + def refresh(self): + self._children = set([]) + self.iscsi_auth_groups = list(self.get_root().get_iscsi_auth_groups()) + if self.iscsi_auth_groups is None: + self.iscsi_auth_groups = [] + for ag in self.iscsi_auth_groups: + UIISCSIAuthGroup(ag, self) + + def ui_command_create(self, tag, secrets=None): + """Add authentication group for CHAP authentication. + + Args: + tag: Authentication group tag (unique, integer > 0). + Optional args: + secrets: Array of secrets objects separated by comma sign, + e.g. user:test secret:test muser:mutual_test msecret:mutual_test + """ + tag = self.ui_eval_param(tag, "number", None) + if secrets: + secrets = [dict(u.split(":") for u in a.split(" ")) + for a in secrets.split(",")] + try: + self.get_root().add_iscsi_auth_group(tag=tag, secrets=secrets) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_delete(self, tag): + """Delete an authentication group. + + Args: + tag: Authentication group tag (unique, integer > 0) + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().delete_iscsi_auth_group(tag=tag) + except JSONRPCException as e: + self.shell.log.error(e.message) + + self.refresh() + + def ui_command_add_secret(self, tag, user, secret, + muser=None, msecret=None): + """Add a secret to an authentication group. + + Args: + tag: Authentication group tag (unique, integer > 0) + user: User name for one-way CHAP authentication + secret: Secret for one-way CHAP authentication + Optional args: + muser: User name for mutual CHAP authentication + msecret: Secret for mutual CHAP authentication + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().add_secret_to_iscsi_auth_group( + tag=tag, user=user, secret=secret, + muser=muser, msecret=msecret) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.refresh() + + def ui_command_delete_secret(self, tag, user): + """Delete a secret from an authentication group. + + Args: + tag: Authentication group tag (unique, integer > 0) + user: User name for one-way CHAP authentication + """ + tag = self.ui_eval_param(tag, "number", None) + try: + self.get_root().delete_secret_from_iscsi_auth_group( + tag=tag, user=user) + except JSONRPCException as e: + self.shell.log.error(e.message) + self.refresh() + + def summary(self): + return "Groups: %s" % len(self.iscsi_auth_groups), None + + +class UIISCSIAuthGroup(UINode): + def __init__(self, ag, parent): + UINode.__init__(self, "group" + str(ag['tag']), parent) + self.ag = ag + self.refresh() + + def refresh(self): + self._children = set([]) + for secret in self.ag['secrets']: + UISCSIAuthSecret(secret, self) + + def summary(self): + return "Secrets: %s" % len(self.ag['secrets']), None + + +class UISCSIAuthSecret(UINode): + def __init__(self, secret, parent): + info = ", ".join("%s=%s" % (key, val) + for key, val in secret.items()) + UINode.__init__(self, info, parent) + self.secret = secret + self.refresh() diff --git a/scripts/spdkcli/ui_root.py b/scripts/spdkcli/ui_root.py index 482f4a301..18ed82ecd 100644 --- a/scripts/spdkcli/ui_root.py +++ b/scripts/spdkcli/ui_root.py @@ -1,5 +1,6 @@ from .ui_node import UINode, UIBdevs, UILvolStores, UIVhosts from .ui_node_nvmf import UINVMf +from .ui_node_iscsi import UIISCSI import rpc.client import rpc from functools import wraps @@ -37,6 +38,7 @@ class UIRoot(UINode): UILvolStores(self) UIVhosts(self) UINVMf(self) + UIISCSI(self) def set_rpc_target(self, s): self.client = rpc.client.JSONRPCClient(s) @@ -301,6 +303,108 @@ class UIRoot(UINode): def nvmf_subsystem_allow_any_host(self, **kwargs): rpc.nvmf.nvmf_subsystem_allow_any_host(self.client, **kwargs) + def get_scsi_devices(self): + if self.is_init: + for device in rpc.iscsi.get_scsi_devices(self.client): + yield ScsiObj(device) + + def get_target_nodes(self): + if self.is_init: + for tg in rpc.iscsi.get_target_nodes(self.client): + yield tg + + @verbose + def construct_target_node(self, **kwargs): + rpc.iscsi.construct_target_node(self.client, **kwargs) + + @verbose + def delete_target_node(self, **kwargs): + rpc.iscsi.delete_target_node(self.client, **kwargs) + + def get_portal_groups(self): + if self.is_init: + for pg in rpc.iscsi.get_portal_groups(self.client): + yield ScsiObj(pg) + + def get_initiator_groups(self): + if self.is_init: + for ig in rpc.iscsi.get_initiator_groups(self.client): + yield ScsiObj(ig) + + @verbose + def construct_portal_group(self, **kwargs): + rpc.iscsi.add_portal_group(self.client, **kwargs) + + @verbose + def delete_portal_group(self, **kwargs): + rpc.iscsi.delete_portal_group(self.client, **kwargs) + + @verbose + def construct_initiator_group(self, **kwargs): + rpc.iscsi.add_initiator_group(self.client, **kwargs) + + @verbose + def delete_initiator_group(self, **kwargs): + rpc.iscsi.delete_initiator_group(self.client, **kwargs) + + @verbose + def get_iscsi_connections(self, **kwargs): + if self.is_init: + for ic in rpc.iscsi.get_iscsi_connections(self.client, **kwargs): + yield ic + + @verbose + def add_initiators_to_initiator_group(self, **kwargs): + rpc.iscsi.add_initiators_to_initiator_group(self.client, **kwargs) + + @verbose + def delete_initiators_from_initiator_group(self, **kwargs): + rpc.iscsi.delete_initiators_from_initiator_group(self.client, **kwargs) + + @verbose + def add_pg_ig_maps(self, **kwargs): + rpc.iscsi.add_pg_ig_maps(self.client, **kwargs) + + @verbose + def delete_pg_ig_maps(self, **kwargs): + rpc.iscsi.delete_pg_ig_maps(self.client, **kwargs) + + @verbose + def add_secret_to_iscsi_auth_group(self, **kwargs): + rpc.iscsi.add_secret_to_iscsi_auth_group(self.client, **kwargs) + + @verbose + def delete_secret_from_iscsi_auth_group(self, **kwargs): + rpc.iscsi.delete_secret_from_iscsi_auth_group(self.client, **kwargs) + + @verbose + def get_iscsi_auth_groups(self, **kwargs): + return rpc.iscsi.get_iscsi_auth_groups(self.client, **kwargs) + + @verbose + def add_iscsi_auth_group(self, **kwargs): + rpc.iscsi.add_iscsi_auth_group(self.client, **kwargs) + + @verbose + def delete_iscsi_auth_group(self, **kwargs): + rpc.iscsi.delete_iscsi_auth_group(self.client, **kwargs) + + @verbose + def set_iscsi_target_node_auth(self, **kwargs): + rpc.iscsi.set_iscsi_target_node_auth(self.client, **kwargs) + + @verbose + def target_node_add_lun(self, **kwargs): + rpc.iscsi.target_node_add_lun(self.client, **kwargs) + + @verbose + def set_iscsi_discovery_auth(self, **kwargs): + rpc.iscsi.set_iscsi_discovery_auth(self.client, **kwargs) + + @verbose + def get_iscsi_global_params(self, **kwargs): + return rpc.iscsi.get_iscsi_global_params(self.client, **kwargs) + class Bdev(object): def __init__(self, bdev_info): @@ -348,3 +452,15 @@ class NvmfSubsystem(object): """ for i in subsystem_info.keys(): setattr(self, i, subsystem_info[i]) + + +class ScsiObj(object): + def __init__(self, device_info): + """ + All class attributes are set based on what information is received + from iscsi related RPC calls. + # TODO: Document in docstring parameters which describe bdevs. + # TODO: Possible improvement: JSON schema might be used here in future + """ + for i in device_info.keys(): + setattr(self, i, device_info[i]) diff --git a/test/spdkcli/match_files/spdkcli_vhost.test.match b/test/spdkcli/match_files/spdkcli_vhost.test.match index 24871d6af..a1ed8dc7c 100644 --- a/test/spdkcli/match_files/spdkcli_vhost.test.match +++ b/test/spdkcli/match_files/spdkcli_vhost.test.match @@ -25,6 +25,30 @@ o- / ........................................................................... | | o- Nvme0n1p3 $(S) [Size=$(FP)G, Not claimed] | o- virtioblk_disk ................................................................................................... [Bdevs: 0] | o- virtioscsi_disk .................................................................................................. [Bdevs: 0] + o- iscsi ................................................................................................................... [...] + | o- auth_groups ..................................................................................................... [Groups: 0] + | o- global_params ......................................................................................................... [...] + | | o- allow_duplicated_isid: False ........................................................................................ [...] + | | o- chap_group: 0 ....................................................................................................... [...] + | | o- default_time2retain: 20 ............................................................................................. [...] + | | o- default_time2wait: 2 ................................................................................................ [...] + | | o- disable_chap: False ................................................................................................. [...] + | | o- error_recovery_level: 0 ............................................................................................. [...] + | | o- first_burst_length: 8192 ............................................................................................ [...] + | | o- immediate_data: True ................................................................................................ [...] + | | o- max_connections_per_session: 2 ...................................................................................... [...] + | | o- max_queue_depth: 64 ................................................................................................. [...] + | | o- max_sessions: 128 ................................................................................................... [...] + | | o- min_connections_per_core: 4 ......................................................................................... [...] + | | o- mutual_chap: False .................................................................................................. [...] + | | o- node_base: iqn.2016-06.io.spdk ...................................................................................... [...] + | | o- nop_in_interval: 30 ................................................................................................. [...] + | | o- nop_timeout: 60 ..................................................................................................... [...] + | | o- require_chap: False ................................................................................................. [...] + | o- initiator_groups ...................................................................................... [Initiator groups: 0] + | o- iscsi_connections .......................................................................................... [Connections: 0] + | o- portal_groups ............................................................................................ [Portal groups: 0] + | o- target_nodes .............................................................................................. [Target nodes: 0] o- lvol_stores .................................................................................................. [Lvol stores: 1] | o- lvs ................................................................................................ [Size=$(FP)M, Free=$(FP)M] o- nvmf .................................................................................................................... [...]