mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
Add virsh commands for secrets APIs
* src/virsh.c: Add virsh commands. * docs/virsh.pod, virsh.1: Update documentation.
This commit is contained in:
parent
03d338608d
commit
2db2c5a186
@ -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
|
||||
|
323
src/virsh.c
323
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
|
||||
*/
|
||||
|
34
virsh.1
34
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
|
||||
|
Loading…
Reference in New Issue
Block a user