The Linux iSCSI initiator toolchain has the dubious feature that
if you ever run the 'sendtargets' command to merely query what
targets are available from a server, the results will be recorded
in /var/lib/iscsi. Any time the '/etc/init.d/iscsi' script runs
in the future, it will then automatically login to all those
targets. /etc/init.d/iscsi is automatically run whenever a NIC
comes online.
So from the moment you ask a server what targets are available,
your client will forever more automatically try to login to all
targets without ever asking if you actually want it todo this.
To stop this stupid behaviour, we need to run
iscsiadm --portal $PORTAL --target $TARGET
--op update --name node.startup --value manual
For every target on the server.
* src/storage/storage_backend_iscsi.c: Disable automatic login
for targets found as a result of a 'sendtargets' command
---
src/storage/storage_backend_iscsi.c | 120 +++++++++++++++++++++++++++++++++--
1 files changed, 113 insertions(+), 7 deletions(-)
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index 51f71af..2a36527 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -450,19 +450,123 @@ virStorageBackendISCSIRescanLUNs(virStoragePoolObjPtr pool
ATTRIBUTE_UNUSED,
return 0;
}
+struct virStorageBackendISCSITargetList {
+ size_t ntargets;
+ char **targets;
+};
+
+static int
+virStorageBackendISCSIGetTargets(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ char **const groups,
+ void *data)
+{
+ struct virStorageBackendISCSITargetList *list = data;
+ char *target;
+
+ if (!(target = strdup(groups[1]))) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (VIR_REALLOC_N(list->targets, list->ntargets + 1) < 0) {
+ VIR_FREE(target);
+ virReportOOMError();
+ return -1;
+ }
+
+ list->targets[list->ntargets] = target;
+ list->ntargets++;
+
+ return 0;
+}
+
+static int
+virStorageBackendISCSITargetAutologin(const char *portal,
+ const char *initiatoriqn,
+ const char *target,
+ bool enable)
+{
+ const char *extraargv[] = { "--op", "update",
+ "--name", "node.startup",
+ "--value", enable ? "automatic" :
"manual",
+ NULL };
+
+ return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv);
+}
+
static int
-virStorageBackendISCSIScanTargets(const char *portal)
+virStorageBackendISCSIScanTargets(const char *portal,
+ const char *initiatoriqn,
+ size_t *ntargetsret,
+ char ***targetsret)
{
- const char *const sendtargets[] = {
- ISCSIADM, "--mode", "discovery", "--type",
"sendtargets", "--portal", portal, NULL
+ /**
+ *
+ * The output of sendtargets is very simple, just two columns,
+ * portal then target name
+ *
+ * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo0.bf6d84
+ * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo1.bf6d84
+ * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo2.bf6d84
+ * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo3.bf6d84
+ */
+ const char *regexes[] = {
+ "^\\s*(\\S+)\\s+(\\S+)\\s*$"
+ };
+ int vars[] = { 2 };
+ const char *const cmdsendtarget[] = {
+ ISCSIADM, "--mode", "discovery", "--type",
"sendtargets",
+ "--portal", portal, NULL
};
- if (virRun(sendtargets, NULL) < 0) {
+ struct virStorageBackendISCSITargetList list;
+ int i;
+ int exitstatus;
+
+ memset(&list, 0, sizeof(list));
+
+ if (virStorageBackendRunProgRegex(NULL, /* No pool for callback */
+ cmdsendtarget,
+ 1,
+ regexes,
+ vars,
+ virStorageBackendISCSIGetTargets,
+ &list,
+ &exitstatus) < 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to run %s to get target list"),
- sendtargets[0]);
+ "%s", _("lvs command failed"));
+ return -1;
+ }
+
+ if (exitstatus != 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("iscsiadm sendtargets command failed with exitstatus
%d"),
+ exitstatus);
return -1;
}
+
+ for (i = 0 ; i < list.ntargets ; i++) {
+ /* We have to ignore failure, because we can't undo
+ * the results of 'sendtargets', unless we go scrubbing
+ * around in the dirt in /var/lib/iscsi.
+ */
+ if (virStorageBackendISCSITargetAutologin(portal,
+ initiatoriqn,
+ list.targets[i], false) < 0)
+ VIR_WARN("Unable to disable auto-login on iSCSI target %s: %s",
+ portal, list.targets[i]);
+ }
+
+ if (ntargetsret && targetsret) {
+ *ntargetsret = list.ntargets;
+ *targetsret = list.targets;
+ } else {
+ for (i = 0 ; i < list.ntargets ; i++) {
+ VIR_FREE(list.targets[i]);
+ }
+ VIR_FREE(list.targets);
+ }
+
return 0;
}
@@ -496,7 +600,9 @@ virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
* iscsiadm doesn't let you login to a target, unless you've
* first issued a 'sendtargets' command to the portal :-(
*/
- if (virStorageBackendISCSIScanTargets(portal) < 0)
+ if (virStorageBackendISCSIScanTargets(portal,
+ pool->def->source.initiator.iqn,
+ NULL, NULL) < 0)
goto cleanup;
if (virStorageBackendISCSIConnection(portal,
--
1.7.2.3