On 27.06.2014 17:11, John Ferlan wrote:
Introduce virStorageAuthDef and friends. Future patches will
merge/utilize
their view of storage source/pool auth/secret definitions.
New API's include:
virStorageAuthDefParse: Parse the "<auth" XML data for either the
domain disk or storage pool returning a
If I were to be narrow-minded OCD libvirt developer, I'd point out:
s,<auth,<auth/>, but since I'm not, I'll leave it :)
virStorageAuthDefPtr
virStorageAuthDefCopy: Copy a virStorageAuthDefPtr - to be used by
the qemuTranslateDiskSourcePoolAuth when it
copies storage pool auth data into domain
disk auth data
virStorageAuthDefFormat: Common output of the "<auth" in the domain
disk or storage pool XML
virStorageAuthDefFree: Free memory associated with virStorageAuthDef
Subsequent patches will utilize the new functions for the domain disk and
storage pools.
Future work in the hostdev pass through can then make use of common data
structures and code.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/libvirt_private.syms | 4 +
src/util/virstoragefile.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/virstoragefile.h | 27 ++++++
3 files changed, 236 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1e1dd84..17dcd67 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1879,6 +1879,10 @@ virStorageGenerateQcowPassphrase;
# util/virstoragefile.h
+virStorageAuthDefCopy;
+virStorageAuthDefFormat;
+virStorageAuthDefFree;
+virStorageAuthDefParse;
I have some doubts it the Format and Parse should be in src/util/. But
since we already have something similar in virstorageencryption.c I
guess we can live with this location too.
virStorageFileCanonicalizePath;
virStorageFileChainGetBroken;
virStorageFileChainLookup;
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index 0c50de1..056e59e 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -29,6 +29,8 @@
#include <fcntl.h>
#include <stdlib.h>
#include "viralloc.h"
+#include "virxml.h"
+#include "viruuid.h"
#include "virerror.h"
#include "virlog.h"
#include "virfile.h"
@@ -97,6 +99,10 @@ VIR_ENUM_IMPL(virStorageSourcePoolMode,
"host",
"direct")
+VIR_ENUM_IMPL(virStorageAuth,
+ VIR_STORAGE_AUTH_TYPE_LAST,
+ "none", "chap", "ceph")
+
enum lv_endian {
LV_LITTLE_ENDIAN = 1, /* 1234 */
LV_BIG_ENDIAN /* 4321 */
@@ -1500,6 +1506,205 @@ virStorageNetHostDefCopy(size_t nhosts,
}
+void
+virStorageAuthDefFree(virStorageAuthDefPtr authdef)
+{
+ if (!authdef)
+ return;
+
+ VIR_FREE(authdef->username);
+ VIR_FREE(authdef->secrettype);
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_USAGE)
+ VIR_FREE(authdef->secret.usage);
+ VIR_FREE(authdef);
+}
+
+
+virStorageAuthDefPtr
+virStorageAuthDefCopy(const virStorageAuthDef *src)
+{
+ virStorageAuthDefPtr ret;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ if (VIR_STRDUP(ret->username, src->username) < 0)
+ goto error;
+ /* Not present for storage pool, but used for disk source */
+ if (src->secrettype)
+ if (VIR_STRDUP(ret->secrettype, src->secrettype) < 0)
+ goto error;
There's no need to check for src->secrettype as VIR_STRDUP accepts NULL.
+ ret->authType = src->authType;
+ ret->secretType = src->secretType;
+ if (ret->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ memcpy(ret->secret.uuid, src->secret.uuid, sizeof(ret->secret.uuid));
+ } else if (ret->secretType == VIR_STORAGE_SECRET_TYPE_USAGE) {
+ if (VIR_STRDUP(ret->secret.usage, src->secret.usage) < 0)
+ goto error;
+ }
+ return ret;
+
+ error:
+ virStorageAuthDefFree(ret);
+ return NULL;
+}
+
I like the explicit copying, but just a suggestion to consider:
{
VIR_ALLOC(ret);
memcpy(ret, src, sizeof(*ret));
VIR_STRDUP(ret->scerettype, src->secrettype);
if (ret->secretType == VIR_STORAGE_SECRET_TYPE_USAGE &&
VIR_STRDUP() < 0)
goto error;
}
I'm worried that if a new item is added into thepy virStorageAuthDef
struct, sooner or later we forget to update the Copy function. With
memcpy() we are safe for shallow copies at least.
+
+static int
+virStorageAuthDefParseSecret(xmlXPathContextPtr ctxt,
+ virStorageAuthDefPtr authdef)
+{
+ char *uuid;
+ char *usage;
+ int ret = -1;
+
+ /* Used by the domain disk xml parsing in order to ensure the
+ * <secret type='%s' value matches the expected secret type for
+ * the style of disk (iscsi is chap, nbd is ceph). For some reason
+ * the virSecretUsageType{From|To}String() cannot be linked here
+ * and because only the domain parsing code cares - just keep
+ * it as a string.
+ */
+ authdef->secrettype = virXPathString("string(./secret/@type)", ctxt);
+
+ uuid = virXPathString("string(./secret/@uuid)", ctxt);
+ usage = virXPathString("string(./secret/@usage)", ctxt);
+ if (uuid == NULL && usage == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing auth secret uuid or usage attribute"));
+ goto cleanup;
+ }
+
+ if (uuid && usage) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("either auth secret uuid or usage expected"));
+ goto cleanup;
+ }
+
+ if (uuid) {
+ if (virUUIDParse(uuid, authdef->secret.uuid) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid auth secret uuid"));
+ goto cleanup;
+ }
+ authdef->secretType = VIR_STORAGE_SECRET_TYPE_UUID;
+ } else {
+ authdef->secret.usage = usage;
+ usage = NULL;
+ authdef->secretType = VIR_STORAGE_SECRET_TYPE_USAGE;
+ }
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(uuid);
+ VIR_FREE(usage);
+ return ret;
+}
+
+
+static virStorageAuthDefPtr
+virStorageAuthDefParseXML(xmlXPathContextPtr ctxt)
+{
+ virStorageAuthDefPtr authdef = NULL;
+ char *username = NULL;
+ char *authtype = NULL;
+
+ if (VIR_ALLOC(authdef) < 0)
+ return NULL;
+
+ if (!(username = virXPathString("string(./@username)", ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing username for auth"));
+ goto error;
+ }
+ authdef->username = username;
+ username = NULL;
+
+ authdef->authType = VIR_STORAGE_AUTH_TYPE_NONE;
+ authtype = virXPathString("string(./@type)", ctxt);
+ if (authtype) {
+ /* Used by the storage pool instead of the secret type field
+ * to define whether chap or ceph being used
+ */
+ if ((authdef->authType = virStorageAuthTypeFromString(authtype)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown auth type '%s'"), authtype);
+ goto error;
+ }
+ VIR_FREE(authtype);
No need for this, as you'll free it just a few lines below.
+ }
+
+ authdef->secretType = VIR_STORAGE_SECRET_TYPE_NONE;
+ if (virStorageAuthDefParseSecret(ctxt, authdef) < 0)
+ goto error;
+
+ return authdef;
+
+ error:
+ VIR_FREE(authtype);
+ VIR_FREE(username);
+ virStorageAuthDefFree(authdef);
+ return NULL;
+}
+
+
+virStorageAuthDefPtr
+virStorageAuthDefParse(xmlDocPtr xml, xmlNodePtr root)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virStorageAuthDefPtr authdef = NULL;
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ authdef = virStorageAuthDefParseXML(ctxt);
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ return authdef;
+}
+
+
+int
+virStorageAuthDefFormat(virBufferPtr buf,
+ virStorageAuthDefPtr authdef)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) {
+ virBufferEscapeString(buf, "<auth username='%s'>\n",
authdef->username);
+ } else {
+ virBufferAsprintf(buf, "<auth type='%s' ",
+ virStorageAuthTypeToString(authdef->authType));
+ virBufferEscapeString(buf, "username='%s'>\n",
authdef->username);
+ }
+
+ virBufferAdjustIndent(buf, 2);
+ if (authdef->secrettype)
+ virBufferAsprintf(buf, "<secret type='%s'",
authdef->secrettype);
+ else
+ virBufferAddLit(buf, "<secret");
+
+ if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+ virUUIDFormat(authdef->secret.uuid, uuidstr);
+ virBufferAsprintf(buf, " uuid='%s'/>\n", uuidstr);
+ } else if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_USAGE) {
+ virBufferEscapeString(buf, " usage='%s'/>\n",
+ authdef->secret.usage);
+ } else {
+ virBufferAddLit(buf, "/>\n");
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</auth>\n");
+
+ return 0;
+}
+
+
virSecurityDeviceLabelDefPtr
virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
const char *model)
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 48c7e02..383ba96 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -193,6 +193,15 @@ typedef virStorageSourcePoolDef *virStorageSourcePoolDefPtr;
typedef enum {
+ VIR_STORAGE_AUTH_TYPE_NONE,
+ VIR_STORAGE_AUTH_TYPE_CHAP,
+ VIR_STORAGE_AUTH_TYPE_CEPHX,
+
+ VIR_STORAGE_AUTH_TYPE_LAST,
+} virStorageAuthType;
+VIR_ENUM_DECL(virStorageAuth)
+
+typedef enum {
VIR_STORAGE_SECRET_TYPE_NONE,
VIR_STORAGE_SECRET_TYPE_UUID,
VIR_STORAGE_SECRET_TYPE_USAGE,
@@ -200,6 +209,19 @@ typedef enum {
VIR_STORAGE_SECRET_TYPE_LAST
} virStorageSecretType;
+typedef struct _virStorageAuthDef virStorageAuthDef;
+typedef virStorageAuthDef *virStorageAuthDefPtr;
+struct _virStorageAuthDef {
+ char *username;
+ char *secrettype; /* <secret type='%s' for disk source */
+ int authType; /* virStorageAuthType */
+ int secretType; /* virStorageSecretType */
+ union {
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *usage;
+ } secret;
+};
Is it necessary to expose the struct or can we hide it in the
virstoragefile.c?
+
typedef struct _virStorageDriverData virStorageDriverData;
typedef virStorageDriverData *virStorageDriverDataPtr;
@@ -307,6 +329,11 @@ int virStorageFileGetLVMKey(const char *path,
int virStorageFileGetSCSIKey(const char *path,
char **key);
+void virStorageAuthDefFree(virStorageAuthDefPtr def);
+virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src);
+virStorageAuthDefPtr virStorageAuthDefParse(xmlDocPtr xml, xmlNodePtr root);
+int virStorageAuthDefFormat(virBufferPtr buf, virStorageAuthDefPtr authdef);
+
virSecurityDeviceLabelDefPtr
virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
const char *model);
Michal