iSCSI¶
iSCSI transports SCSI commands over TCP/IP, allowing remote block storage to
appear as local SCSI devices. The initiator side uses iscsiadm to discover
targets, log in to sessions, and manage node records (a "node" in open-iscsi
is a target+portal+interface tuple).
Device Management¶
sts.iscsi.device
¶
iSCSI device management.
IscsiDevice
pydantic-model
¶
Bases: StorageDevice, NetworkDevice
iSCSI block device accessed over a network connection.
Show JSON schema:
{
"additionalProperties": false,
"description": "iSCSI block device accessed over a network connection.",
"properties": {
"path": {
"format": "path",
"title": "Path",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"ip": {
"title": "Ip",
"type": "string"
},
"port": {
"default": 3260,
"maximum": 65535,
"minimum": 1,
"title": "Port",
"type": "integer"
},
"size": {
"title": "Size",
"type": "integer"
},
"model": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Model"
},
"target_iqn": {
"title": "Target Iqn",
"type": "string"
},
"initiator_iqn": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Initiator Iqn"
}
},
"required": [
"path",
"name",
"ip",
"size",
"target_iqn"
],
"title": "IscsiDevice",
"type": "object"
}
Fields:
-
model(str | None) -
name(str) -
path(Path) -
size(int) -
ip(str) -
target_iqn(str) -
port(int) -
initiator_iqn(str | None)
Validators:
-
_derive_fields
Source code in sts_libs/src/sts/iscsi/device.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
portal
property
¶
Portal address in IP:Port format.
discover(ip, port=3260)
classmethod
¶
Discover available target IQNs via SendTargets discovery.
Source code in sts_libs/src/sts/iscsi/device.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
get_all()
classmethod
¶
Get all iSCSI devices from active sessions.
Source code in sts_libs/src/sts/iscsi/device.py
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
Session Management¶
sts.iscsi.session
¶
iSCSI session management.
IscsiSession
pydantic-model
¶
Bases: StsBaseModel
iSCSI session representation.
Show JSON schema:
{
"additionalProperties": false,
"description": "iSCSI session representation.",
"properties": {
"session_id": {
"minLength": 1,
"title": "Session Id",
"type": "string"
},
"target_iqn": {
"minLength": 1,
"title": "Target Iqn",
"type": "string"
},
"portal": {
"title": "Portal",
"type": "string"
}
},
"required": [
"session_id",
"target_iqn",
"portal"
],
"title": "IscsiSession",
"type": "object"
}
Fields:
-
session_id(str) -
target_iqn(str) -
portal(str)
Source code in sts_libs/src/sts/iscsi/session.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
get_all()
classmethod
¶
Get list of all iSCSI sessions.
Source code in sts_libs/src/sts/iscsi/session.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
get_by_portal(portal)
classmethod
¶
Get sessions matching portal address.
Source code in sts_libs/src/sts/iscsi/session.py
146 147 148 149 | |
get_by_target(target_iqn)
classmethod
¶
Get sessions matching target IQN.
Source code in sts_libs/src/sts/iscsi/session.py
141 142 143 144 | |
get_data()
¶
Get session data from iscsiadm -m session -r <sid> -S.
Returns a plain dict rather than a typed model on purpose: the set of
keys varies with the negotiated iSCSI session/connection parameters
(see PARAM_MAP in .parameters), so a fixed model would need every
key declared optional — no safer than a dict, and it would make
callers that iterate all keys (e.g. get_parameters()) more awkward.
This mirrors the NVMe JSON methods, which keep the same raw-dict
exception for the same reason.
Source code in sts_libs/src/sts/iscsi/session.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
get_data_p2()
¶
Get session data with print level 2.
Source code in sts_libs/src/sts/iscsi/session.py
73 74 75 76 77 78 79 80 81 82 83 84 85 | |
get_disks()
¶
Get list of disks attached to session.
Source code in sts_libs/src/sts/iscsi/session.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
get_parameters()
¶
Get negotiated parameters from session.
Source code in sts_libs/src/sts/iscsi/session.py
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
logout()
¶
Log out from session.
Source code in sts_libs/src/sts/iscsi/session.py
42 43 44 45 46 47 48 | |
SessionDisk
pydantic-model
¶
Bases: ReportModel
SCSI disk exposed through an iSCSI session (parsed from -P 3 output).
Show JSON schema:
{
"description": "SCSI disk exposed through an iSCSI session (parsed from -P 3 output).",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"state": {
"title": "State",
"type": "string"
},
"scsi_n": {
"title": "Scsi N",
"type": "string"
},
"channel": {
"title": "Channel",
"type": "string"
},
"id": {
"title": "Id",
"type": "string"
},
"lun": {
"title": "Lun",
"type": "string"
}
},
"required": [
"name",
"state",
"scsi_n",
"channel",
"id",
"lun"
],
"title": "SessionDisk",
"type": "object"
}
Fields:
-
name(str) -
state(str) -
scsi_n(str) -
channel(str) -
id(str) -
lun(str)
Source code in sts_libs/src/sts/iscsi/session.py
20 21 22 23 24 25 26 27 28 29 30 31 32 | |
is_running()
¶
Check if disk state is 'running'.
Source code in sts_libs/src/sts/iscsi/session.py
30 31 32 | |
Configuration¶
sts.iscsi.config
¶
iSCSI configuration models and initiator name management.
IscsiConfig
pydantic-model
¶
Bases: StsBaseModel
iSCSI configuration.
Show JSON schema:
{
"$defs": {
"IscsiInterface": {
"additionalProperties": false,
"description": "iSCSI interface configuration.",
"properties": {
"iscsi_ifacename": {
"minLength": 1,
"title": "Iscsi Ifacename",
"type": "string"
},
"ipaddress": {
"title": "Ipaddress",
"type": "string"
},
"hwaddress": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Hwaddress"
}
},
"required": [
"iscsi_ifacename",
"ipaddress"
],
"title": "IscsiInterface",
"type": "object"
},
"IscsiNode": {
"additionalProperties": false,
"description": "An open-iscsi node record \u2014 a portal on a target.\n\nPer the iscsiadm manpage, open-iscsi uses \"node\" to refer to\na portal on a target \u2014 identified by targetname + portal + interface.",
"properties": {
"target_iqn": {
"title": "Target Iqn",
"type": "string"
},
"portal": {
"title": "Portal",
"type": "string"
},
"iface": {
"default": "default",
"title": "Iface",
"type": "string"
}
},
"required": [
"target_iqn",
"portal"
],
"title": "IscsiNode",
"type": "object"
}
},
"additionalProperties": false,
"description": "iSCSI configuration.",
"properties": {
"initiatorname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Initiatorname"
},
"ifaces": {
"items": {
"$ref": "#/$defs/IscsiInterface"
},
"title": "Ifaces",
"type": "array"
},
"targets": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/IscsiNode"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Targets"
},
"driver": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Driver"
}
},
"title": "IscsiConfig",
"type": "object"
}
Fields:
-
initiatorname(str | None) -
ifaces(list[IscsiInterface]) -
targets(list[IscsiNode] | None) -
driver(str | None)
Source code in sts_libs/src/sts/iscsi/config.py
71 72 73 74 75 76 77 | |
IscsiInterface
pydantic-model
¶
Bases: StsBaseModel
iSCSI interface configuration.
Show JSON schema:
{
"additionalProperties": false,
"description": "iSCSI interface configuration.",
"properties": {
"iscsi_ifacename": {
"minLength": 1,
"title": "Iscsi Ifacename",
"type": "string"
},
"ipaddress": {
"title": "Ipaddress",
"type": "string"
},
"hwaddress": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Hwaddress"
}
},
"required": [
"iscsi_ifacename",
"ipaddress"
],
"title": "IscsiInterface",
"type": "object"
}
Fields:
-
iscsi_ifacename(str) -
ipaddress(str) -
hwaddress(str | None)
Source code in sts_libs/src/sts/iscsi/config.py
63 64 65 66 67 68 | |
IscsidConfig
¶
Bases: Config
Manages /etc/iscsi/iscsid.conf settings.
Source code in sts_libs/src/sts/iscsi/config.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
disable_chap()
¶
Remove all CHAP settings from iscsid.conf and restart iscsid.
Source code in sts_libs/src/sts/iscsi/config.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | |
set_chap(username, password, mutual_username=None, mutual_password=None)
¶
Configure CHAP authentication in iscsid.conf and restart iscsid.
Source code in sts_libs/src/sts/iscsi/config.py
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | |
rand_iscsi_string(length)
¶
Generate random string using iSCSI-allowed characters (RFC 7143 Section 6.1).
Source code in sts_libs/src/sts/iscsi/config.py
29 30 31 | |
set_initiatorname(name)
¶
Write initiator name to /etc/iscsi/initiatorname.iscsi and restart iscsid.
Source code in sts_libs/src/sts/iscsi/config.py
48 49 50 51 52 53 54 55 56 57 58 59 60 | |
wait_for_iscsid()
¶
Verify iscsid is responsive after a restart.
iscsid is a Type=notify systemd service, so systemctl restart already blocks until READY=1. This check confirms iscsiadm can talk to the daemon — a lightweight sanity gate rather than a polling loop.
Source code in sts_libs/src/sts/iscsi/config.py
34 35 36 37 38 39 40 41 42 43 44 45 | |
iSCSI Administration¶
sts.iscsi.iscsiadm
¶
Wrapper for the iscsiadm command line tool.
IscsiAdm
pydantic-model
¶
Bases: StsBaseModel
Wrapper for iscsiadm command line tool.
Attributes:
| Name | Type | Description |
|---|---|---|
debug_level |
Literal[0, 1, 2, 3, 4, 5, 6, 7, 8]
|
Debug verbosity level passed to iscsiadm via |
Show JSON schema:
{
"additionalProperties": false,
"description": "Wrapper for iscsiadm command line tool.\n\nAttributes:\n debug_level: Debug verbosity level passed to iscsiadm via ``--debug``.",
"properties": {
"debug_level": {
"default": 0,
"enum": [
0,
1,
2,
3,
4,
5,
6,
7,
8
],
"title": "Debug Level",
"type": "integer"
}
},
"title": "IscsiAdm",
"type": "object"
}
Fields:
-
debug_level(Literal[0, 1, 2, 3, 4, 5, 6, 7, 8])
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
discovery(portal='127.0.0.1', type='st', interface=None, **kwargs)
¶
Run SendTargets discovery.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
iface(op, iface, name=None, value=None)
¶
Run iscsiadm iface command.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
39 40 41 42 43 44 45 46 | |
iface_exists(iface)
¶
Check if iSCSI interface exists.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
60 61 62 | |
iface_update(iface, name, value)
¶
Update iSCSI interface parameter.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
48 49 50 | |
iface_update_ip(iface, ip)
¶
Update iSCSI interface IP address.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
56 57 58 | |
iface_update_iqn(iface, iqn)
¶
Update iSCSI interface initiator name.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
52 53 54 | |
node(**kwargs)
¶
Run iscsiadm node command.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
79 80 81 | |
node_login(**kwargs)
¶
Log in to a node.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
83 84 85 86 87 | |
node_logout(**kwargs)
¶
Log out from a node.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
89 90 91 92 93 | |
node_logoutall(how='all')
¶
Log out from all nodes.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
95 96 97 | |
session(**kwargs)
¶
Run iscsiadm session command.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
99 100 101 | |
session_logout(sid)
¶
Log out a session by its ID.
Source code in sts_libs/src/sts/iscsi/iscsiadm.py
103 104 105 | |
sts.iscsi.node
¶
iSCSI node record (target + portal + iface).
IscsiNode
pydantic-model
¶
Bases: StsBaseModel
An open-iscsi node record — a portal on a target.
Per the iscsiadm manpage, open-iscsi uses "node" to refer to a portal on a target — identified by targetname + portal + interface.
Show JSON schema:
{
"additionalProperties": false,
"description": "An open-iscsi node record \u2014 a portal on a target.\n\nPer the iscsiadm manpage, open-iscsi uses \"node\" to refer to\na portal on a target \u2014 identified by targetname + portal + interface.",
"properties": {
"target_iqn": {
"title": "Target Iqn",
"type": "string"
},
"portal": {
"title": "Portal",
"type": "string"
},
"iface": {
"default": "default",
"title": "Iface",
"type": "string"
}
},
"required": [
"target_iqn",
"portal"
],
"title": "IscsiNode",
"type": "object"
}
Fields:
-
target_iqn(str) -
portal(str) -
iface(str)
Source code in sts_libs/src/sts/iscsi/node.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
login()
¶
Log in to target and wait for SCSI devices to settle.
Source code in sts_libs/src/sts/iscsi/node.py
29 30 31 32 33 34 35 36 37 38 39 | |
logout()
¶
Log out from target.
Source code in sts_libs/src/sts/iscsi/node.py
41 42 43 | |
sts.iscsi.parameters
¶
iSCSI parameter negotiation verification per RFC 7143.
verify_parameter(param, target_value, initiator_value, negotiated_value, max_burst_length=None)
¶
Verify negotiated parameter value against RFC 7143 rules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
param
|
str
|
Parameter name |
required |
target_value
|
str
|
Target's offered value |
required |
initiator_value
|
str
|
Initiator's offered value |
required |
negotiated_value
|
str
|
Actually negotiated value |
required |
max_burst_length
|
tuple[str, str] | None
|
(target, initiator) MaxBurstLength values for FirstBurstLength validation |
None
|
Source code in sts_libs/src/sts/iscsi/parameters.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | |