summaryrefslogtreecommitdiffstats
path: root/src/spdk/scripts/spdkcli/ui_node_iscsi.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/scripts/spdkcli/ui_node_iscsi.py')
-rw-r--r--src/spdk/scripts/spdkcli/ui_node_iscsi.py639
1 files changed, 639 insertions, 0 deletions
diff --git a/src/spdk/scripts/spdkcli/ui_node_iscsi.py b/src/spdk/scripts/spdkcli/ui_node_iscsi.py
new file mode 100644
index 000000000..938cb7ab4
--- /dev/null
+++ b/src/spdk/scripts/spdkcli/ui_node_iscsi.py
@@ -0,0 +1,639 @@
+from configshell_fb import ExecutionError
+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([])
+ iscsi_global_params = self.get_root().iscsi_get_options()
+ if not iscsi_global_params:
+ return
+ for param, val in 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)
+ self.get_root().iscsi_set_discovery_auth(
+ chap_group=chap_group, disable_chap=disable_chap,
+ require_chap=require_chap, mutual_chap=mutual_chap)
+
+
+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.scsi_devices = list()
+ self.refresh()
+
+ def refresh(self):
+ self._children = set([])
+ self.target_nodes = list(self.get_root().iscsi_get_target_nodes())
+ self.scsi_devices = list(self.get_root().scsi_get_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 delete(self, name):
+ self.get_root().iscsi_delete_target_node(target_node_name=name)
+
+ 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)
+ self.get_root().iscsi_create_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)
+
+ 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.
+ """
+ self.delete(name)
+
+ def ui_command_delete_all(self):
+ """Delete all target nodes"""
+ rpc_messages = ""
+ for device in self.scsi_devices:
+ try:
+ self.delete(device.device_name)
+ except JSONRPCException as e:
+ rpc_messages += e.message
+ if rpc_messages:
+ raise JSONRPCException(rpc_messages)
+
+ 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)
+ self.get_root().iscsi_target_node_add_lun(
+ name=name, bdev_name=bdev_name, lun_id=lun_id)
+
+ 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)
+ self.get_root().iscsi_target_node_set_auth(
+ name=self.device.device_name, chap_group=chap_group,
+ disable_chap=disable_chap,
+ require_chap=require_chap, mutual_chap=mutual_chap)
+
+ def ui_command_iscsi_target_node_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)})
+ self.get_root().iscsi_target_node_add_pg_ig_maps(
+ pg_ig_maps=pg_ig_maps, name=self.device.device_name)
+
+ def ui_command_iscsi_target_node_remove_pg_ig_maps(self, pg_ig_mappings):
+ """Remove PG-IG maps from 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)})
+ self.get_root().iscsi_target_node_remove_pg_ig_maps(
+ pg_ig_maps=pg_ig_maps, name=self.device.device_name)
+
+ 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 delete(self, tag):
+ self.get_root().iscsi_delete_portal_group(tag=tag)
+
+ def ui_command_create(self, tag, portal_list):
+ """Add a portal group.
+
+ Args:
+ portals: List of portals e.g. ip:port ip2:port2
+ tag: Portal group tag (unique, integer > 0)
+ """
+ portals = []
+ for portal in portal_list.strip().split(" "):
+ host = portal
+ cpumask = None
+ if "@" in portal:
+ host, cpumask = portal.split("@")
+ if ":" not in host:
+ raise ExecutionError("Incorrect format of portal group. Port is missing."
+ "Use 'help create' to see the command syntax.")
+ host, port = host.rsplit(":", -1)
+ portals.append({'host': host, 'port': port})
+ if cpumask:
+ print("WARNING: Specifying a CPU mask for portal groups is no longer supported. Ignoring.")
+ tag = self.ui_eval_param(tag, "number", None)
+ self.get_root().construct_portal_group(tag=tag, portals=portals)
+
+ def ui_command_delete(self, tag):
+ """Delete a portal group with given tag (unique, integer > 0))"""
+ tag = self.ui_eval_param(tag, "number", None)
+ self.delete(tag)
+
+ def ui_command_delete_all(self):
+ """Delete all portal groups"""
+ rpc_messages = ""
+ for pg in self.pgs:
+ try:
+ self.delete(pg.tag)
+ except JSONRPCException as e:
+ rpc_messages += e.message
+ if rpc_messages:
+ raise JSONRPCException(rpc_messages)
+
+ def refresh(self):
+ self._children = set([])
+ self.pgs = list(self.get_root().iscsi_get_portal_groups())
+ for pg in self.pgs:
+ try:
+ UIPortalGroup(pg, self)
+ except JSONRPCException as e:
+ self.shell.log.error(e.message)
+
+ 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'], self)
+
+ def summary(self):
+ return "Portals: %d" % len(self.pg.portals), None
+
+
+class UIPortal(UINode):
+ def __init__(self, host, port, parent):
+ UINode.__init__(self, "host=%s, port=%s" % (
+ host, port), parent)
+ self.refresh()
+
+
+class UIInitiatorGroups(UINode):
+ def __init__(self, parent):
+ UINode.__init__(self, "initiator_groups", parent)
+ self.refresh()
+
+ def delete(self, tag):
+ self.get_root().iscsi_delete_initiator_group(tag=tag)
+
+ 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)
+ self.get_root().construct_initiator_group(
+ tag=tag, initiators=initiator_list.split(" "),
+ netmasks=netmask_list.split(" "))
+
+ 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)
+ self.delete(tag)
+
+ def ui_command_delete_all(self):
+ """Delete all initiator groups"""
+ rpc_messages = ""
+ for ig in self.igs:
+ try:
+ self.delete(ig.tag)
+ except JSONRPCException as e:
+ rpc_messages += e.message
+ if rpc_messages:
+ raise JSONRPCException(rpc_messages)
+
+ 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)
+ self.get_root().iscsi_initiator_group_add_initiators(
+ tag=tag, initiators=initiators.split(" "),
+ netmasks=netmasks.split(" "))
+
+ 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(" ")
+ self.get_root().iscsi_initiator_group_remove_initiators(
+ tag=tag, initiators=initiators,
+ netmasks=netmasks)
+
+ def refresh(self):
+ self._children = set([])
+ self.igs = list(self.get_root().iscsi_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().iscsi_get_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.items():
+ 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().iscsi_get_auth_groups())
+ if self.iscsi_auth_groups is None:
+ self.iscsi_auth_groups = []
+ for ag in self.iscsi_auth_groups:
+ UIISCSIAuthGroup(ag, self)
+
+ def delete(self, tag):
+ self.get_root().iscsi_delete_auth_group(tag=tag)
+
+ def delete_secret(self, tag, user):
+ self.get_root().iscsi_auth_group_remove_secret(
+ tag=tag, user=user)
+
+ 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(",")]
+ self.get_root().iscsi_create_auth_group(tag=tag, secrets=secrets)
+
+ 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)
+ self.delete(tag)
+
+ def ui_command_delete_all(self):
+ """Delete all authentication groups."""
+ rpc_messages = ""
+ for iscsi_auth_group in self.iscsi_auth_groups:
+ try:
+ self.delete(iscsi_auth_group['tag'])
+ except JSONRPCException as e:
+ rpc_messages += e.message
+ if rpc_messages:
+ raise JSONRPCException(rpc_messages)
+
+ 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)
+ self.get_root().iscsi_auth_group_add_secret(
+ tag=tag, user=user, secret=secret,
+ muser=muser, msecret=msecret)
+
+ 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)
+ self.delete_secret(tag, user)
+
+ def ui_command_delete_secret_all(self, tag):
+ """Delete all secrets from an authentication group.
+
+ Args:
+ tag: Authentication group tag (unique, integer > 0)
+ """
+ rpc_messages = ""
+ tag = self.ui_eval_param(tag, "number", None)
+ for ag in self.iscsi_auth_groups:
+ if ag['tag'] == tag:
+ for secret in ag['secrets']:
+ try:
+ self.delete_secret(tag, secret['user'])
+ except JSONRPCException as e:
+ rpc_messages += e.message
+ if rpc_messages:
+ raise JSONRPCException(rpc_messages)
+
+ 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_list = ["%s=%s" % (key, val)
+ for key, val in secret.items()]
+ info_list.sort(reverse=True)
+ info = ", ".join(info_list)
+ UINode.__init__(self, info, parent)
+ self.secret = secret
+ self.refresh()