[libvirt] [PATCH 05/10] Secret manipulation step 8: Add virsh commands

Miloslav Trmač mitr at redhat.com
Mon Sep 7 14:12:40 UTC 2009


* src/virsh.c: Add virsh commands.
* docs/virsh.pod, virsh.1: Update documentation.
---
 docs/virsh.pod |   43 ++++++++
 src/virsh.c    |  323 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 virsh.1        |   34 ++++++-
 3 files changed, 399 insertions(+), 1 deletions(-)

diff --git a/docs/virsh.pod b/docs/virsh.pod
index 10bb991..55ec64a 100644
--- a/docs/virsh.pod
+++ b/docs/virsh.pod
@@ -543,6 +543,49 @@ Convert a network name to network UUID.
 
 =back
 
+=head1 SECRET COMMMANDS
+
+The following commands manipulate "secrets" (e.g. passwords, passphrases and
+encryption keys).  Libvirt can store secrets independently from their use, and
+other objects (e.g. volumes or domains) can refer to the secrets for encryption
+or possibly other uses.  Secrets are identified using an UUID.  See
+L<http://libvirt.org/formatsecret.html> for documentation of the XML format
+used to represent properties of secrets.
+
+=over 4
+
+=item B<secret-define> I<file>
+
+Create a secret with the properties specified in I<file>, with no associated
+secret value.  If I<file> does not specify a UUID, choose one automatically.
+If I<file> specifies an UUID of an existing secret, replace its properties by
+properties defined in I<file>, without affecting the secret value.
+
+=item B<secret-dumpxml> I<secret>
+
+Output properties of I<secret> (specified by its UUID) as an XML dump to stdout.
+
+=item B<secret-set-value> I<secret> I<base64>
+
+Set the value associated with I<secret> (specified by its UUID) to the value
+Base64-encoded value I<base64>.
+
+=item B<secret-get-value> I<secret>
+
+Output the value associated with I<secret> (specified by its UUID) to stdout,
+encoded using Base64.
+
+=item B<secret-undefine> I<secret>
+
+Delete a I<secret> (specified by its UUID), including the associated value, if
+any.
+
+=item B<secret-list>
+
+Output a list of UUIDs of known secrets to stdout.
+
+=back
+
 =head1 ENVIRONMENT
 
 The following environment variables can be set to alter the behaviour
diff --git a/src/virsh.c b/src/virsh.c
index 910d860..9dc8857 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -41,6 +41,7 @@
 #endif
 
 #include "internal.h"
+#include "base64.h"
 #include "buf.h"
 #include "console.h"
 #include "util.h"
@@ -271,6 +272,9 @@ static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
     vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name,     \
                            VSH_BYUUID|VSH_BYNAME)
 
+static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
+                                        char **name);
+
 static void vshPrintExtra(vshControl *ctl, const char *format, ...)
     ATTRIBUTE_FMT_PRINTF(2, 3);
 static void vshDebug(vshControl *ctl, int level, const char *format, ...)
@@ -5249,9 +5253,291 @@ cmdVolPath(vshControl *ctl, const vshCmd *cmd)
 }
 
 
+/*
+ * "secret-define" command
+ */
+static const vshCmdInfo info_secret_define[] = {
+    {"help", gettext_noop("define or modify a secret from an XML file")},
+    {"desc", gettext_noop("Define or modify a secret.")},
+    {NULL, NULL}
+};
 
+static const vshCmdOptDef opts_secret_define[] = {
+    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing secret attributes in XML")},
+    {NULL, 0, 0, NULL}
+};
 
+static int
+cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
+{
+    char *from, *buffer, *uuid;
+    virSecretPtr res;
 
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    from = vshCommandOptString(cmd, "file", NULL);
+    if (!from)
+        return FALSE;
+
+    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
+        return FALSE;
+
+    res = virSecretDefineXML(ctl->conn, buffer, 0);
+    free (buffer);
+
+    if (res == NULL) {
+        vshError(ctl, FALSE, _("Failed to set attributes from %s"), from);
+        return FALSE;
+    }
+    uuid = virSecretGetUUIDString(res);
+    if (uuid == NULL) {
+        vshError(ctl, FALSE, "%s",
+                 _("Failed to get UUID of created secret"));
+        virSecretFree(res);
+        return FALSE;
+    }
+    vshPrint(ctl, _("Secret %s created\n"), uuid);
+    free(uuid);
+    virSecretFree(res);
+    return TRUE;
+}
+
+/*
+ * "secret-dumpxml" command
+ */
+static const vshCmdInfo info_secret_dumpxml[] = {
+    {"help", gettext_noop("secret attributes in XML")},
+    {"desc", gettext_noop("Output attributes of a secret as an XML dump to stdout.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_dumpxml[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    int ret = FALSE;
+    char *xml;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return FALSE;
+
+    xml = virSecretGetXMLDesc(secret, 0);
+    if (xml == NULL)
+        goto cleanup;
+    printf("%s", xml);
+    free(xml);
+    ret = TRUE;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-set-value" command
+ */
+static const vshCmdInfo info_secret_set_value[] = {
+    {"help", gettext_noop("set a secret value")},
+    {"desc", gettext_noop("Set a secret value.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_set_value[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")},
+    {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("base64-encoded secret value")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    size_t value_size;
+    char *base64, *value;
+    int found, res, ret = FALSE;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return FALSE;
+
+    base64 = vshCommandOptString(cmd, "base64", &found);
+    if (!base64)
+        goto cleanup;
+
+    if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
+        vshError(ctl, FALSE, _("Invalid base64 data"));
+        goto cleanup;
+    }
+    if (value == NULL) {
+        vshError(ctl, FALSE, "%s", _("Failed to allocate memory"));
+        return FALSE;
+    }
+
+    res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
+    memset(value, 0, value_size);
+    free (value);
+
+    if (res != 0) {
+        vshError(ctl, FALSE, "%s", _("Failed to set secret value"));
+        goto cleanup;
+    }
+    vshPrint(ctl, "%s", _("Secret value set\n"));
+    ret = TRUE;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-get-value" command
+ */
+static const vshCmdInfo info_secret_get_value[] = {
+    {"help", gettext_noop("Output a secret value")},
+    {"desc", gettext_noop("Output a secret value to stdout.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_get_value[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    char *base64;
+    unsigned char *value;
+    size_t value_size;
+    int ret = FALSE;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return FALSE;
+
+    value = virSecretGetValue(secret, &value_size, 0);
+    if (value == NULL)
+        goto cleanup;
+
+    base64_encode_alloc((char *)value, value_size, &base64);
+    memset(value, 0, value_size);
+    free(value);
+
+    if (base64 == NULL) {
+        vshError(ctl, FALSE, "%s", _("Failed to allocate memory"));
+        goto cleanup;
+    }
+    printf("%s", base64);
+    memset(base64, 0, strlen(base64));
+    free(base64);
+    ret = TRUE;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-undefine" command
+ */
+static const vshCmdInfo info_secret_undefine[] = {
+    {"help", gettext_noop("undefine a secret")},
+    {"desc", gettext_noop("Undefine a secret.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_undefine[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    int ret = FALSE;
+    char *uuid;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    secret = vshCommandOptSecret(ctl, cmd, &uuid);
+    if (secret == NULL)
+        return FALSE;
+
+    if (virSecretUndefine(secret) < 0) {
+        vshError(ctl, FALSE, _("Failed to delete secret %s"), uuid);
+        goto cleanup;
+    }
+    vshPrint(ctl, _("Secret %s deleted\n"), uuid);
+    ret = TRUE;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-list" command
+ */
+static const vshCmdInfo info_secret_list[] = {
+    {"help", gettext_noop("list secrets")},
+    {"desc", gettext_noop("Returns a list of secrets")},
+    {NULL, NULL}
+};
+
+static int
+cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+    int maxuuids = 0, i;
+    char **uuids = NULL;
+
+    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    maxuuids = virConnectNumOfSecrets(ctl->conn);
+    if (maxuuids < 0) {
+        vshError(ctl, FALSE, "%s", _("Failed to list secrets"));
+        return FALSE;
+    }
+    uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
+
+    maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
+    if (maxuuids < 0) {
+        vshError(ctl, FALSE, "%s", _("Failed to list secrets"));
+        free(uuids);
+        return FALSE;
+    }
+
+    qsort(uuids, maxuuids, sizeof(char *), namesorter);
+
+    vshPrintExtra(ctl, "%s\n", _("UUID"));
+    vshPrintExtra(ctl, "-----------------------------------------\n");
+
+    for (i = 0; i < maxuuids; i++) {
+        vshPrint(ctl, "%-36s\n", uuids[i]);
+        free(uuids[i]);
+    }
+    free(uuids);
+    return TRUE;
+}
 
 
 /*
@@ -6931,6 +7217,14 @@ static const vshCmdDef commands[] = {
     {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
     {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
 
+    {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
+    {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
+    {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
+    {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
+    {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
+    {"secret-list", cmdSecretList, NULL, info_secret_list},
+
+
 #ifndef WIN32
     {"pwd", cmdPwd, NULL, info_pwd},
 #endif
@@ -7490,6 +7784,35 @@ vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
     return vol;
 }
 
+static virSecretPtr
+vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, char **name)
+{
+    virSecretPtr secret = NULL;
+    char *n;
+    const char *optname = "secret";
+
+    if (!cmd_has_option (ctl, cmd, optname))
+        return NULL;
+
+    n = vshCommandOptString(cmd, optname, NULL);
+    if (n == NULL) {
+        vshError(ctl, FALSE, "%s", _("undefined secret UUID"));
+        return NULL;
+    }
+
+    vshDebug(ctl, 5, "%s: found option <%s>: %s\n", cmd->def->name, optname, n);
+
+    if (name != NULL)
+        *name = n;
+
+    secret = virSecretLookupByUUIDString(ctl->conn, n);
+
+    if (secret == NULL)
+        vshError(ctl, FALSE, _("failed to get secret '%s'"), n);
+
+    return secret;
+}
+
 /*
  * Executes command(s) and returns return code from last command
  */
diff --git a/virsh.1 b/virsh.1
index 0a5b1c1..5731b4c 100644
--- a/virsh.1
+++ b/virsh.1
@@ -132,7 +132,7 @@
 .\" ========================================================================
 .\"
 .IX Title "VIRSH 1"
-.TH VIRSH 1 "2009-08-11" "libvirt-0.7.0" "Virtualization Support"
+.TH VIRSH 1 "2009-08-20" "libvirt-0.7.0" "Virtualization Support"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -593,6 +593,38 @@ Undefine the configuration for an inactive network.
 .IP "\fBnet-uuid\fR \fInetwork-name\fR" 4
 .IX Item "net-uuid network-name"
 Convert a network name to network \s-1UUID\s0.
+.SH "SECRET COMMMANDS"
+.IX Header "SECRET COMMMANDS"
+The following commands manipulate \*(L"secrets\*(R" (e.g. passwords, passphrases and
+encryption keys).  Libvirt can store secrets independently from their use, and
+other objects (e.g. volumes or domains) can refer to the secrets for encryption
+or possibly other uses.  Secrets are identified using an \s-1UUID\s0.  See
+<http://libvirt.org/formatsecret.html> for documentation of the \s-1XML\s0 format
+used to represent properties of secrets.
+.IP "\fBsecret-define\fR \fIfile\fR" 4
+.IX Item "secret-define file"
+Create a secret with the properties specified in \fIfile\fR, with no associated
+secret value.  If \fIfile\fR does not specify a \s-1UUID\s0, choose one automatically.
+If \fIfile\fR specifies an \s-1UUID\s0 of an existing secret, replace its properties by
+properties defined in \fIfile\fR, without affecting the secret value.
+.IP "\fBsecret-dumpxml\fR \fIsecret\fR" 4
+.IX Item "secret-dumpxml secret"
+Output properties of \fIsecret\fR (specified by its \s-1UUID\s0) as an \s-1XML\s0 dump to stdout.
+.IP "\fBsecret-set-value\fR \fIsecret\fR \fIbase64\fR" 4
+.IX Item "secret-set-value secret base64"
+Set the value associated with \fIsecret\fR (specified by its \s-1UUID\s0) to the value
+Base64\-encoded value \fIbase64\fR.
+.IP "\fBsecret-get-value\fR \fIsecret\fR" 4
+.IX Item "secret-get-value secret"
+Output the value associated with \fIsecret\fR (specified by its \s-1UUID\s0) to stdout,
+encoded using Base64.
+.IP "\fBsecret-undefine\fR \fIsecret\fR" 4
+.IX Item "secret-undefine secret"
+Delete a \fIsecret\fR (specified by its \s-1UUID\s0), including the associated value, if
+any.
+.IP "\fBsecret-list\fR" 4
+.IX Item "secret-list"
+Output a list of UUIDs of known secrets to stdout.
 .SH "ENVIRONMENT"
 .IX Header "ENVIRONMENT"
 The following environment variables can be set to alter the behaviour
-- 
1.6.2.5




More information about the libvir-list mailing list