Remove the 'StorageBackend' from names of the functions and fix indentation. --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 9 + src/storage/storage_backend_iscsi.c | 498 ++---------------------------------- src/storage/storage_backend_iscsi.h | 4 - src/util/viriscsi.c | 498 ++++++++++++++++++++++++++++++++++++ src/util/viriscsi.h | 52 ++++ 7 files changed, 588 insertions(+), 475 deletions(-) create mode 100644 src/util/viriscsi.c create mode 100644 src/util/viriscsi.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index efac7b2..5a4112a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -168,6 +168,7 @@ src/util/virhostdev.c src/util/viridentity.c src/util/virinitctl.c src/util/viriptables.c +src/util/viriscsi.c src/util/virjson.c src/util/virkeyfile.c src/util/virlockspace.c diff --git a/src/Makefile.am b/src/Makefile.am index 4fdd871..55427ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,6 +113,7 @@ UTIL_SOURCES = \ util/viridentity.c util/viridentity.h \ util/virinitctl.c util/virinitctl.h \ util/viriptables.c util/viriptables.h \ + util/viriscsi.c util/viriscsi.h \ util/virjson.c util/virjson.h \ util/virkeycode.c util/virkeycode.h \ util/virkeyfile.c util/virkeyfile.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c7e024d..d72a9af 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1359,6 +1359,15 @@ iptablesRemoveUdpInput; iptablesRemoveUdpOutput; +# util/viriscsi.h +virISCSIConnectionLogin; +virISCSIConnectionLogout; +virISCSIGetSession; +virISCSINodeUpdate; +virISCSIRescanLUNs; +virISCSIScanTargets; + + # util/virjson.h virJSONValueArrayAppend; virJSONValueArrayGet; diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index b7a0380..7e7ffad 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -26,8 +26,6 @@ #include <dirent.h> #include <sys/wait.h> #include <string.h> -#include <stdio.h> -#include <regex.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> @@ -40,9 +38,9 @@ #include "vircommand.h" #include "virerror.h" #include "virfile.h" +#include "viriscsi.h" #include "virlog.h" #include "virobject.h" -#include "virrandom.h" #include "virstring.h" #include "viruuid.h" @@ -79,306 +77,14 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source) return portal; } -struct virStorageBackendISCSISessionData { - char *session; - const char *devpath; -}; - -static int -virStorageBackendISCSIExtractSession(char **const groups, - void *opaque) -{ - struct virStorageBackendISCSISessionData *data = opaque; - - if (STREQ(groups[1], data->devpath)) - return VIR_STRDUP(data->session, groups[0]); - return 0; -} - -static char * -virStorageBackendISCSIGetSession(const char *devpath, - bool probe) -{ - /* - * # iscsiadm --mode session - * tcp: [1] 192.168.122.170:3260,1 demo-tgt-b - * tcp: [2] 192.168.122.170:3260,1 demo-tgt-a - * - * Pull out 2nd and 4th fields - */ - const char *regexes[] = { - "^tcp:\\s+\\[(\\S+)\\]\\s+\\S+\\s+(\\S+).*$" - }; - int vars[] = { - 2, - }; - struct virStorageBackendISCSISessionData cbdata = { - .session = NULL, - .devpath = devpath, - }; - - virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL); - - if (virCommandRunRegex(cmd, - 1, - regexes, - vars, - virStorageBackendISCSIExtractSession, - &cbdata, NULL) < 0) - goto cleanup; - - if (cbdata.session == NULL && !probe) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot find session")); - goto cleanup; - } - -cleanup: - virCommandFree(cmd); - return cbdata.session; -} static char * virStorageBackendISCSISession(virStoragePoolObjPtr pool, bool probe) { - return virStorageBackendISCSIGetSession(pool->def->source.devices[0].path, probe); -} - - -#define LINE_SIZE 4096 - -static int -virStorageBackendIQNFound(const char *initiatoriqn, - char **ifacename) -{ - int ret = IQN_MISSING, fd = -1; - char ebuf[64]; - FILE *fp = NULL; - char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL; - virCommandPtr cmd = virCommandNewArgList(ISCSIADM, - "--mode", "iface", NULL); - - if (VIR_ALLOC_N(line, LINE_SIZE) != 0) { - ret = IQN_ERROR; - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not allocate memory for output of '%s'"), - ISCSIADM); - goto out; - } - - memset(line, 0, LINE_SIZE); - - virCommandSetOutputFD(cmd, &fd); - if (virCommandRunAsync(cmd, NULL) < 0) { - ret = IQN_ERROR; - goto out; - } - - if ((fp = VIR_FDOPEN(fd, "r")) == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to open stream for file descriptor " - "when reading output from '%s': '%s'"), - ISCSIADM, virStrerror(errno, ebuf, sizeof(ebuf))); - ret = IQN_ERROR; - goto out; - } - - while (fgets(line, LINE_SIZE, fp) != NULL) { - newline = strrchr(line, '\n'); - if (newline == NULL) { - ret = IQN_ERROR; - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected line > %d characters " - "when parsing output of '%s'"), - LINE_SIZE, ISCSIADM); - goto out; - } - *newline = '\0'; - - iqn = strrchr(line, ','); - if (iqn == NULL) { - continue; - } - iqn++; - - if (STREQ(iqn, initiatoriqn)) { - token = strchr(line, ' '); - if (!token) { - ret = IQN_ERROR; - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Missing space when parsing output " - "of '%s'"), ISCSIADM); - goto out; - } - if (VIR_STRNDUP(*ifacename, line, token - line) < 0) { - ret = IQN_ERROR; - goto out; - } - VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn); - ret = IQN_FOUND; - break; - } - } - - if (virCommandWait(cmd, NULL) < 0) - ret = IQN_ERROR; - -out: - if (ret == IQN_MISSING) { - VIR_DEBUG("Could not find interface with IQN '%s'", iqn); - } - - VIR_FREE(line); - VIR_FORCE_FCLOSE(fp); - VIR_FORCE_CLOSE(fd); - virCommandFree(cmd); - - return ret; -} - - -static int -virStorageBackendCreateIfaceIQN(const char *initiatoriqn, - char **ifacename) -{ - int ret = -1, exitstatus = -1; - char *temp_ifacename; - virCommandPtr cmd = NULL; - - if (virAsprintf(&temp_ifacename, - "libvirt-iface-%08llx", - (unsigned long long)virRandomBits(30)) < 0) - return -1; - - VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'", - temp_ifacename, initiatoriqn); - - cmd = virCommandNewArgList(ISCSIADM, - "--mode", "iface", - "--interface", temp_ifacename, - "--op", "new", - NULL); - /* Note that we ignore the exitstatus. Older versions of iscsiadm - * tools returned an exit status of > 0, even if they succeeded. - * We will just rely on whether the interface got created - * properly. */ - if (virCommandRun(cmd, &exitstatus) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to run command '%s' to create new iscsi interface"), - ISCSIADM); - goto cleanup; - } - virCommandFree(cmd); - - cmd = virCommandNewArgList(ISCSIADM, - "--mode", "iface", - "--interface", temp_ifacename, - "--op", "update", - "--name", "iface.initiatorname", - "--value", - initiatoriqn, - NULL); - /* Note that we ignore the exitstatus. Older versions of iscsiadm tools - * returned an exit status of > 0, even if they succeeded. We will just - * rely on whether iface file got updated properly. */ - if (virCommandRun(cmd, &exitstatus) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to run command '%s' to update iscsi interface with IQN '%s'"), - ISCSIADM, initiatoriqn); - goto cleanup; - } - - /* Check again to make sure the interface was created. */ - if (virStorageBackendIQNFound(initiatoriqn, ifacename) != IQN_FOUND) { - VIR_DEBUG("Failed to find interface '%s' with IQN '%s' " - "after attempting to create it", - &temp_ifacename[0], initiatoriqn); - goto cleanup; - } else { - VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully", - *ifacename, initiatoriqn); - } - - ret = 0; - -cleanup: - virCommandFree(cmd); - VIR_FREE(temp_ifacename); - if (ret != 0) - VIR_FREE(*ifacename); - return ret; -} - - - -static int -virStorageBackendISCSIConnection(const char *portal, - const char *initiatoriqn, - const char *target, - const char **extraargv) -{ - int ret = -1; - const char *const baseargv[] = { - ISCSIADM, - "--mode", "node", - "--portal", portal, - "--targetname", target, - NULL - }; - virCommandPtr cmd; - char *ifacename = NULL; - - cmd = virCommandNewArgs(baseargv); - virCommandAddArgSet(cmd, extraargv); - - if (initiatoriqn) { - switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) { - case IQN_FOUND: - VIR_DEBUG("ifacename: '%s'", ifacename); - break; - case IQN_MISSING: - if (virStorageBackendCreateIfaceIQN(initiatoriqn, - &ifacename) != 0) { - goto cleanup; - } - break; - case IQN_ERROR: - default: - goto cleanup; - } - virCommandAddArgList(cmd, "--interface", ifacename, NULL); - } - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - ret = 0; - -cleanup: - virCommandFree(cmd); - VIR_FREE(ifacename); - - return ret; -} - -static int -virStorageBackendISCSIConnectionLogin(const char *portal, - const char *initiatoriqn, - const char *target) -{ - const char *extraargv[] = { "--login", NULL }; - return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv); + return virISCSIGetSession(pool->def->source.devices[0].path, probe); } -static int -virStorageBackendISCSIConnectionLogout(const char *portal, - const char *initiatoriqn, - const char *target) -{ - const char *extraargv[] = { "--logout", NULL }; - return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv); -} static int virStorageBackendISCSIGetHostNumber(const char *sysfs_path, @@ -448,124 +154,6 @@ virStorageBackendISCSIFindLUs(virStoragePoolObjPtr pool, return retval; } -static int -virStorageBackendISCSIRescanLUNs(const char *session) -{ - virCommandPtr cmd = virCommandNewArgList(ISCSIADM, - "--mode", "session", - "-r", session, - "-R", - NULL); - int ret = virCommandRun(cmd, NULL); - virCommandFree(cmd); - return ret; -} - -struct virStorageBackendISCSITargetList { - size_t ntargets; - char **targets; -}; - -static int -virStorageBackendISCSIGetTargets(char **const groups, - void *data) -{ - struct virStorageBackendISCSITargetList *list = data; - char *target; - - if (VIR_STRDUP(target, groups[1]) < 0) - return -1; - - if (VIR_APPEND_ELEMENT(list->targets, list->ntargets, target) < 0) { - VIR_FREE(target); - return -1; - } - - 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, - const char *initiatoriqn, - size_t *ntargetsret, - char ***targetsret) -{ - /** - * - * 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 }; - struct virStorageBackendISCSITargetList list; - size_t i; - int ret = -1; - virCommandPtr cmd = virCommandNewArgList(ISCSIADM, - "--mode", "discovery", - "--type", "sendtargets", - "--portal", portal, - NULL); - - memset(&list, 0, sizeof(list)); - - if (virCommandRunRegex(cmd, - 1, - regexes, - vars, - virStorageBackendISCSIGetTargets, - &list, NULL) < 0) - goto cleanup; - - 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); - } - - ret = 0; -cleanup: - virCommandFree(cmd); - return ret; -} - static char * virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, @@ -606,9 +194,9 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, if (!(portal = virStorageBackendISCSIPortal(source))) goto cleanup; - if (virStorageBackendISCSIScanTargets(portal, - source->initiator.iqn, - &ntargets, &targets) < 0) + if (virISCSIScanTargets(portal, + source->initiator.iqn, + &ntargets, &targets) < 0) goto cleanup; if (VIR_ALLOC_N(list.sources, ntargets) < 0) @@ -683,38 +271,6 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED, return ret; } -static int -virStorageBackendISCSINodeUpdate(const char *portal, - const char *target, - const char *name, - const char *value) -{ - virCommandPtr cmd = NULL; - int status; - int ret = -1; - - cmd = virCommandNewArgList(ISCSIADM, - "--mode", "node", - "--portal", portal, - "--target", target, - "--op", "update", - "--name", name, - "--value", value, - NULL); - - /* Ignore non-zero status. */ - if (virCommandRun(cmd, &status) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to update '%s' of node mode for target '%s'"), - name, target); - goto cleanup; - } - - ret = 0; -cleanup: - virCommandFree(cmd); - return ret; -} static int virStorageBackendISCSISetAuth(const char *portal, @@ -784,18 +340,18 @@ virStorageBackendISCSISetAuth(const char *portal, goto cleanup; } - if (virStorageBackendISCSINodeUpdate(portal, - def->source.devices[0].path, - "node.session.auth.authmethod", - "CHAP") < 0 || - virStorageBackendISCSINodeUpdate(portal, - def->source.devices[0].path, - "node.session.auth.username", - chap.username) < 0 || - virStorageBackendISCSINodeUpdate(portal, - def->source.devices[0].path, - "node.session.auth.password", - (const char *)secret_value) < 0) + if (virISCSINodeUpdate(portal, + def->source.devices[0].path, + "node.session.auth.authmethod", + "CHAP") < 0 || + virISCSINodeUpdate(portal, + def->source.devices[0].path, + "node.session.auth.username", + chap.username) < 0 || + virISCSINodeUpdate(portal, + def->source.devices[0].path, + "node.session.auth.password", + (const char *)secret_value) < 0) goto cleanup; ret = 0; @@ -840,17 +396,17 @@ virStorageBackendISCSIStartPool(virConnectPtr conn, * iscsiadm doesn't let you login to a target, unless you've * first issued a 'sendtargets' command to the portal :-( */ - if (virStorageBackendISCSIScanTargets(portal, - pool->def->source.initiator.iqn, - NULL, NULL) < 0) + if (virISCSIScanTargets(portal, + pool->def->source.initiator.iqn, + NULL, NULL) < 0) goto cleanup; if (virStorageBackendISCSISetAuth(portal, conn, pool->def) < 0) goto cleanup; - if (virStorageBackendISCSIConnectionLogin(portal, - pool->def->source.initiator.iqn, - pool->def->source.devices[0].path) < 0) + if (virISCSIConnectionLogin(portal, + pool->def->source.initiator.iqn, + pool->def->source.devices[0].path) < 0) goto cleanup; } ret = 0; @@ -871,7 +427,7 @@ virStorageBackendISCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, if ((session = virStorageBackendISCSISession(pool, false)) == NULL) goto cleanup; - if (virStorageBackendISCSIRescanLUNs(session) < 0) + if (virISCSIRescanLUNs(session) < 0) goto cleanup; if (virStorageBackendISCSIFindLUs(pool, session) < 0) goto cleanup; @@ -895,9 +451,9 @@ virStorageBackendISCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED, if ((portal = virStorageBackendISCSIPortal(&pool->def->source)) == NULL) return -1; - if (virStorageBackendISCSIConnectionLogout(portal, - pool->def->source.initiator.iqn, - pool->def->source.devices[0].path) < 0) + if (virISCSIConnectionLogout(portal, + pool->def->source.initiator.iqn, + pool->def->source.devices[0].path) < 0) goto cleanup; ret = 0; diff --git a/src/storage/storage_backend_iscsi.h b/src/storage/storage_backend_iscsi.h index 910a795..da3b22c 100644 --- a/src/storage/storage_backend_iscsi.h +++ b/src/storage/storage_backend_iscsi.h @@ -28,8 +28,4 @@ extern virStorageBackend virStorageBackendISCSI; -# define IQN_FOUND 1 -# define IQN_MISSING 0 -# define IQN_ERROR -1 - #endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */ diff --git a/src/util/viriscsi.c b/src/util/viriscsi.c new file mode 100644 index 0000000..18a595f --- /dev/null +++ b/src/util/viriscsi.c @@ -0,0 +1,498 @@ +/* + * viriscsi.c: helper APIs for managing iSCSI + * + * Copyright (C) 2007-2014 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <regex.h> +#include <stdio.h> + +#include "viriscsi.h" + +#include "viralloc.h" +#include "vircommand.h" +#include "virerror.h" +#include "virfile.h" +#include "virlog.h" +#include "virrandom.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.iscsi"); + + +struct virISCSISessionData { + char *session; + const char *devpath; +}; + + +static int +virISCSIExtractSession(char **const groups, + void *opaque) +{ + struct virISCSISessionData *data = opaque; + + if (STREQ(groups[1], data->devpath)) + return VIR_STRDUP(data->session, groups[0]); + return 0; +} + + +char * +virISCSIGetSession(const char *devpath, + bool probe) +{ + /* + * # iscsiadm --mode session + * tcp: [1] 192.168.122.170:3260,1 demo-tgt-b + * tcp: [2] 192.168.122.170:3260,1 demo-tgt-a + * + * Pull out 2nd and 4th fields + */ + const char *regexes[] = { + "^tcp:\\s+\\[(\\S+)\\]\\s+\\S+\\s+(\\S+).*$" + }; + int vars[] = { + 2, + }; + struct virISCSISessionData cbdata = { + .session = NULL, + .devpath = devpath, + }; + + virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL); + + if (virCommandRunRegex(cmd, + 1, + regexes, + vars, + virISCSIExtractSession, + &cbdata, NULL) < 0) + goto cleanup; + + if (cbdata.session == NULL && !probe) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot find session")); + goto cleanup; + } + +cleanup: + virCommandFree(cmd); + return cbdata.session; +} + + + +#define LINE_SIZE 4096 +#define IQN_FOUND 1 +#define IQN_MISSING 0 +#define IQN_ERROR -1 + +static int +virStorageBackendIQNFound(const char *initiatoriqn, + char **ifacename) +{ + int ret = IQN_MISSING, fd = -1; + char ebuf[64]; + FILE *fp = NULL; + char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL; + virCommandPtr cmd = virCommandNewArgList(ISCSIADM, + "--mode", "iface", NULL); + + if (VIR_ALLOC_N(line, LINE_SIZE) != 0) { + ret = IQN_ERROR; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not allocate memory for output of '%s'"), + ISCSIADM); + goto out; + } + + memset(line, 0, LINE_SIZE); + + virCommandSetOutputFD(cmd, &fd); + if (virCommandRunAsync(cmd, NULL) < 0) { + ret = IQN_ERROR; + goto out; + } + + if ((fp = VIR_FDOPEN(fd, "r")) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open stream for file descriptor " + "when reading output from '%s': '%s'"), + ISCSIADM, virStrerror(errno, ebuf, sizeof(ebuf))); + ret = IQN_ERROR; + goto out; + } + + while (fgets(line, LINE_SIZE, fp) != NULL) { + newline = strrchr(line, '\n'); + if (newline == NULL) { + ret = IQN_ERROR; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected line > %d characters " + "when parsing output of '%s'"), + LINE_SIZE, ISCSIADM); + goto out; + } + *newline = '\0'; + + iqn = strrchr(line, ','); + if (iqn == NULL) { + continue; + } + iqn++; + + if (STREQ(iqn, initiatoriqn)) { + token = strchr(line, ' '); + if (!token) { + ret = IQN_ERROR; + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing space when parsing output " + "of '%s'"), ISCSIADM); + goto out; + } + if (VIR_STRNDUP(*ifacename, line, token - line) < 0) { + ret = IQN_ERROR; + goto out; + } + VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn); + ret = IQN_FOUND; + break; + } + } + + if (virCommandWait(cmd, NULL) < 0) + ret = IQN_ERROR; + +out: + if (ret == IQN_MISSING) { + VIR_DEBUG("Could not find interface with IQN '%s'", iqn); + } + + VIR_FREE(line); + VIR_FORCE_FCLOSE(fp); + VIR_FORCE_CLOSE(fd); + virCommandFree(cmd); + + return ret; +} + + +static int +virStorageBackendCreateIfaceIQN(const char *initiatoriqn, + char **ifacename) +{ + int ret = -1, exitstatus = -1; + char *temp_ifacename; + virCommandPtr cmd = NULL; + + if (virAsprintf(&temp_ifacename, + "libvirt-iface-%08llx", + (unsigned long long)virRandomBits(30)) < 0) + return -1; + + VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'", + temp_ifacename, initiatoriqn); + + cmd = virCommandNewArgList(ISCSIADM, + "--mode", "iface", + "--interface", temp_ifacename, + "--op", "new", + NULL); + /* Note that we ignore the exitstatus. Older versions of iscsiadm + * tools returned an exit status of > 0, even if they succeeded. + * We will just rely on whether the interface got created + * properly. */ + if (virCommandRun(cmd, &exitstatus) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to run command '%s' to create new iscsi interface"), + ISCSIADM); + goto cleanup; + } + virCommandFree(cmd); + + cmd = virCommandNewArgList(ISCSIADM, + "--mode", "iface", + "--interface", temp_ifacename, + "--op", "update", + "--name", "iface.initiatorname", + "--value", + initiatoriqn, + NULL); + /* Note that we ignore the exitstatus. Older versions of iscsiadm tools + * returned an exit status of > 0, even if they succeeded. We will just + * rely on whether iface file got updated properly. */ + if (virCommandRun(cmd, &exitstatus) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to run command '%s' to update iscsi interface with IQN '%s'"), + ISCSIADM, initiatoriqn); + goto cleanup; + } + + /* Check again to make sure the interface was created. */ + if (virStorageBackendIQNFound(initiatoriqn, ifacename) != IQN_FOUND) { + VIR_DEBUG("Failed to find interface '%s' with IQN '%s' " + "after attempting to create it", + &temp_ifacename[0], initiatoriqn); + goto cleanup; + } else { + VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully", + *ifacename, initiatoriqn); + } + + ret = 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(temp_ifacename); + if (ret != 0) + VIR_FREE(*ifacename); + return ret; +} + + +static int +virISCSIConnection(const char *portal, + const char *initiatoriqn, + const char *target, + const char **extraargv) +{ + int ret = -1; + const char *const baseargv[] = { + ISCSIADM, + "--mode", "node", + "--portal", portal, + "--targetname", target, + NULL + }; + virCommandPtr cmd; + char *ifacename = NULL; + + cmd = virCommandNewArgs(baseargv); + virCommandAddArgSet(cmd, extraargv); + + if (initiatoriqn) { + switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) { + case IQN_FOUND: + VIR_DEBUG("ifacename: '%s'", ifacename); + break; + case IQN_MISSING: + if (virStorageBackendCreateIfaceIQN(initiatoriqn, + &ifacename) != 0) { + goto cleanup; + } + break; + case IQN_ERROR: + default: + goto cleanup; + } + virCommandAddArgList(cmd, "--interface", ifacename, NULL); + } + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(ifacename); + + return ret; +} + + +int +virISCSIConnectionLogin(const char *portal, + const char *initiatoriqn, + const char *target) +{ + const char *extraargv[] = { "--login", NULL }; + return virISCSIConnection(portal, initiatoriqn, target, extraargv); +} + + +int +virISCSIConnectionLogout(const char *portal, + const char *initiatoriqn, + const char *target) +{ + const char *extraargv[] = { "--logout", NULL }; + return virISCSIConnection(portal, initiatoriqn, target, extraargv); +} + + +int +virISCSIRescanLUNs(const char *session) +{ + virCommandPtr cmd = virCommandNewArgList(ISCSIADM, + "--mode", "session", + "-r", session, + "-R", + NULL); + int ret = virCommandRun(cmd, NULL); + virCommandFree(cmd); + return ret; +} + + +struct virISCSITargetList { + size_t ntargets; + char **targets; +}; + + +static int +virISCSIGetTargets(char **const groups, + void *data) +{ + struct virISCSITargetList *list = data; + char *target; + + if (VIR_STRDUP(target, groups[1]) < 0) + return -1; + + if (VIR_APPEND_ELEMENT(list->targets, list->ntargets, target) < 0) { + VIR_FREE(target); + return -1; + } + + return 0; +} + + +static int +virISCSITargetAutologin(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 virISCSIConnection(portal, initiatoriqn, target, extraargv); +} + + +int +virISCSIScanTargets(const char *portal, + const char *initiatoriqn, + size_t *ntargetsret, + char ***targetsret) +{ + /** + * + * 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 }; + struct virISCSITargetList list; + size_t i; + int ret = -1; + virCommandPtr cmd = virCommandNewArgList(ISCSIADM, + "--mode", "discovery", + "--type", "sendtargets", + "--portal", portal, + NULL); + + memset(&list, 0, sizeof(list)); + + if (virCommandRunRegex(cmd, + 1, + regexes, + vars, + virISCSIGetTargets, + &list, NULL) < 0) + goto cleanup; + + 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 (virISCSITargetAutologin(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); + } + + ret = 0; +cleanup: + virCommandFree(cmd); + return ret; +} + + +int +virISCSINodeUpdate(const char *portal, + const char *target, + const char *name, + const char *value) +{ + virCommandPtr cmd = NULL; + int status; + int ret = -1; + + cmd = virCommandNewArgList(ISCSIADM, + "--mode", "node", + "--portal", portal, + "--target", target, + "--op", "update", + "--name", name, + "--value", value, + NULL); + + /* Ignore non-zero status. */ + if (virCommandRun(cmd, &status) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to update '%s' of node mode for target '%s'"), + name, target); + goto cleanup; + } + + ret = 0; +cleanup: + virCommandFree(cmd); + return ret; +} diff --git a/src/util/viriscsi.h b/src/util/viriscsi.h new file mode 100644 index 0000000..462e56a --- /dev/null +++ b/src/util/viriscsi.h @@ -0,0 +1,52 @@ +/* + * viriscsi.h: helper APIs for managing iSCSI + * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_ISCSI_H__ +# define __VIR_ISCSI_H__ + +# include "internal.h" + +char * +virISCSIGetSession(const char *devpath, + bool probe); + +int +virISCSIConnectionLogin(const char *portal, + const char *initiatoriqn, + const char *target); +int +virISCSIConnectionLogout(const char *portal, + const char *initiatoriqn, + const char *target); +int +virISCSIRescanLUNs(const char *session); + +int +virISCSIScanTargets(const char *portal, + const char *initiatoriqn, + size_t *ntargetsret, + char ***targetsret); +int +virISCSINodeUpdate(const char *portal, + const char *target, + const char *name, + const char *value); +#endif -- 1.8.3.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list