---
generator/actions.ml | 20 ++++++++---
src/drives.c | 86 +++++++++++++++++++++++++++++++++++++-----------
src/guestfs-internal.h | 2 ++
src/guestfs.pod | 5 ++-
src/launch-libvirt.c | 3 ++
5 files changed, 90 insertions(+), 26 deletions(-)
diff --git a/generator/actions.ml b/generator/actions.ml
index daea6b6..b0b4be7 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -1247,7 +1247,7 @@ not all belong to a single logical operating system
{ defaults with
name = "add_drive";
- style = RErr, [String "filename"], [OBool "readonly"; OString
"format"; OString "iface"; OString "name"; OString
"label"; OString "protocol"; OStringList "server"; OString
"username"];
+ style = RErr, [String "filename"], [OBool "readonly"; OString
"format"; OString "iface"; OString "name"; OString
"label"; OString "protocol"; OStringList "server"; OString
"username"; OString "secret"];
once_had_no_optargs = true;
blocking = false;
fish_alias = ["add"];
@@ -1353,6 +1353,7 @@ See also: L<guestfs(3)/NETWORK BLOCK DEVICE>.
Connect to the Ceph (librbd/RBD) server.
The C<server> parameter must also be supplied - see below.
The C<username> parameter may be supplied. See below.
+The C<secret> parameter may be supplied. See below.
See also: L<guestfs(3)/CEPH>.
@@ -1404,12 +1405,21 @@ for the protocol is used (see C</etc/services>).
For the C<ssh> and C<rbd> protocols only, this specifies the remote
username.
-If not given, then the local username is used for C<ssh>, and 'admin' is
used
-for C<rbd>. But note this sometimes may give unexpected results, for example
-if using the libvirt backend and if the libvirt backend is configured to start
-the qemu appliance as a special user such as C<qemu.qemu>. If in doubt,
+If not given, then the local username is used for C<ssh>, and no authentication
+is attempted for ceph. But note this sometimes may give unexpected results, for
+example if using the libvirt backend and if the libvirt backend is configured to
+start the qemu appliance as a special user such as C<qemu.qemu>. If in doubt,
specify the remote username you want.
+=item C<secret>
+
+For the C<rbd> protocol only, this specifies the 'secret' to use when
+connecting to the remote device.
+
+If not given, then a secret matching the given username will be looked up in the
+default keychain locations, or if no username is given, then no authentication
+will be used.
+
=back" };
{ defaults with
diff --git a/src/drives.c b/src/drives.c
index a510e1e..1429050 100644
--- a/src/drives.c
+++ b/src/drives.c
@@ -107,7 +107,8 @@ static struct drive *
create_drive_non_file (guestfs_h *g,
enum drive_protocol protocol,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
@@ -120,6 +121,7 @@ create_drive_non_file (guestfs_h *g,
drv->src.nr_servers = nr_servers;
drv->src.u.exportname = safe_strdup (g, exportname);
drv->src.username = username ? safe_strdup (g, username) : NULL;
+ drv->src.secret = secret ? safe_strdup (g, secret) : NULL;
drv->readonly = readonly;
drv->format = format ? safe_strdup (g, format) : NULL;
@@ -136,7 +138,8 @@ create_drive_non_file (guestfs_h *g,
static struct drive *
create_drive_gluster (guestfs_h *g,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
@@ -146,6 +149,11 @@ create_drive_gluster (guestfs_h *g,
error (g, _("gluster: you cannot specify a username with this protocol"));
return NULL;
}
+ if (secret != NULL) {
+ error (g, _("gluster: you cannot specify a secret with this protocol"));
+ return NULL;
+ }
+
if (nr_servers != 1) {
error (g, _("gluster: you must specify exactly one server"));
@@ -165,7 +173,8 @@ create_drive_gluster (guestfs_h *g,
}
return create_drive_non_file (g, drive_protocol_gluster,
- servers, nr_servers, exportname, username,
+ servers, nr_servers, exportname,
+ username, secret,
readonly, format, iface, name, disk_label,
use_cache_none);
}
@@ -185,7 +194,8 @@ nbd_port (void)
static struct drive *
create_drive_nbd (guestfs_h *g,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
@@ -195,6 +205,10 @@ create_drive_nbd (guestfs_h *g,
error (g, _("nbd: you cannot specify a username with this protocol"));
return NULL;
}
+ if (secret != NULL) {
+ error (g, _("nbd: you cannot specify a secret with this protocol"));
+ return NULL;
+ }
if (nr_servers != 1) {
error (g, _("nbd: you must specify exactly one server"));
@@ -205,7 +219,8 @@ create_drive_nbd (guestfs_h *g,
servers[0].port = nbd_port ();
return create_drive_non_file (g, drive_protocol_nbd,
- servers, nr_servers, exportname, username,
+ servers, nr_servers, exportname,
+ username, secret,
readonly, format, iface, name, disk_label,
use_cache_none);
}
@@ -213,7 +228,8 @@ create_drive_nbd (guestfs_h *g,
static struct drive *
create_drive_rbd (guestfs_h *g,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
@@ -244,7 +260,8 @@ create_drive_rbd (guestfs_h *g,
}
return create_drive_non_file (g, drive_protocol_rbd,
- servers, nr_servers, exportname, username,
+ servers, nr_servers, exportname,
+ username, secret,
readonly, format, iface, name, disk_label,
use_cache_none);
}
@@ -252,7 +269,8 @@ create_drive_rbd (guestfs_h *g,
static struct drive *
create_drive_sheepdog (guestfs_h *g,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
@@ -264,6 +282,10 @@ create_drive_sheepdog (guestfs_h *g,
error (g, _("sheepdog: you cannot specify a username with this
protocol"));
return NULL;
}
+ if (secret != NULL) {
+ error (g, _("sheepdog: you cannot specify a secret with this protocol"));
+ return NULL;
+ }
for (i = 0; i < nr_servers; ++i) {
if (servers[i].transport != drive_transport_none &&
@@ -283,7 +305,8 @@ create_drive_sheepdog (guestfs_h *g,
}
return create_drive_non_file (g, drive_protocol_sheepdog,
- servers, nr_servers, exportname, username,
+ servers, nr_servers, exportname,
+ username, secret,
readonly, format, iface, name, disk_label,
use_cache_none);
}
@@ -291,12 +314,18 @@ create_drive_sheepdog (guestfs_h *g,
static struct drive *
create_drive_ssh (guestfs_h *g,
struct drive_server *servers, size_t nr_servers,
- const char *exportname, const char *username,
+ const char *exportname,
+ const char *username, const char *secret,
bool readonly, const char *format,
const char *iface, const char *name,
const char *disk_label,
bool use_cache_none)
{
+ if (secret != NULL) {
+ error (g, _("ssh: you cannot specify a secret with this protocol"));
+ return NULL;
+ }
+
if (nr_servers != 1) {
error (g, _("ssh: you must specify exactly one server"));
return NULL;
@@ -319,7 +348,8 @@ create_drive_ssh (guestfs_h *g,
}
return create_drive_non_file (g, drive_protocol_ssh,
- servers, nr_servers, exportname, username,
+ servers, nr_servers, exportname,
+ username, secret,
readonly, format, iface, name, disk_label,
use_cache_none);
}
@@ -690,6 +720,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
size_t nr_servers = 0;
struct drive_server *servers = NULL;
const char *username;
+ const char *secret;
int use_cache_none;
struct drive *drv;
size_t i, drv_index;
@@ -720,6 +751,8 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
}
username = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK
? optargs->username : NULL;
+ secret = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK
+ ? optargs->secret : NULL;
if (format && !valid_format_iface (format)) {
error (g, _("%s parameter is empty or contains disallowed characters"),
@@ -750,6 +783,11 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
free_drive_servers (servers, nr_servers);
return -1;
}
+ if (secret != NULL) {
+ error (g, _("you cannot specify a secret with file-backed disks"));
+ free_drive_servers (servers, nr_servers);
+ return -1;
+ }
if (STREQ (filename, "/dev/null"))
drv = create_drive_dev_null (g, readonly, format, iface, name,
@@ -775,27 +813,32 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
}
}
else if (STREQ (protocol, "gluster")) {
- drv = create_drive_gluster (g, servers, nr_servers, filename, username,
+ drv = create_drive_gluster (g, servers, nr_servers, filename,
+ username, secret,
readonly, format, iface, name,
disk_label, false);
}
else if (STREQ (protocol, "nbd")) {
- drv = create_drive_nbd (g, servers, nr_servers, filename, username,
+ drv = create_drive_nbd (g, servers, nr_servers, filename,
+ username, secret,
readonly, format, iface, name,
disk_label, false);
}
else if (STREQ (protocol, "rbd")) {
- drv = create_drive_rbd (g, servers, nr_servers, filename, username,
+ drv = create_drive_rbd (g, servers, nr_servers, filename,
+ username, secret,
readonly, format, iface, name,
disk_label, false);
}
else if (STREQ (protocol, "sheepdog")) {
- drv = create_drive_sheepdog (g, servers, nr_servers, filename, username,
+ drv = create_drive_sheepdog (g, servers, nr_servers, filename,
+ username, secret,
readonly, format, iface, name,
disk_label, false);
}
else if (STREQ (protocol, "ssh")) {
- drv = create_drive_ssh (g, servers, nr_servers, filename, username,
+ drv = create_drive_ssh (g, servers, nr_servers, filename,
+ username, secret,
readonly, format, iface, name,
disk_label, false);
}
@@ -1083,7 +1126,7 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct
drive_source *src)
case drive_protocol_rbd: {
/* build the list of all the mon hosts */
- CLEANUP_FREE char *mon_host = NULL, *username = NULL;
+ CLEANUP_FREE char *mon_host = NULL, *username = NULL, *secret = NULL;
char *auth;
size_t n = 0;
for (int i = 0; i < src->nr_servers; i++) {
@@ -1113,13 +1156,15 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct
drive_source *src)
if (src->username)
username = safe_asprintf (g, ":id=%s", src->username);
- if (username)
+ if (src->secret)
+ secret = safe_asprintf (g, ":key=%s", src->secret);
+ if (username || secret)
auth = ":auth_supported=cephx\\;none";
else
auth = ":auth_supported=none";
- return safe_asprintf (g, "rbd:%s:mon_host=%s%s%s", src->u.exportname,
mon_host,
- username ? username : "", auth);
+ return safe_asprintf (g, "rbd:%s:mon_host=%s%s%s%s", src->u.exportname,
mon_host,
+ username ? username : "", auth, secret ? secret : "");
}
case drive_protocol_sheepdog:
@@ -1155,6 +1200,7 @@ guestfs___free_drive_source (struct drive_source *src)
if (src) {
free (src->u.path);
free (src->username);
+ free (src->secret);
free_drive_servers (src->servers, src->nr_servers);
}
}
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index e13c498..6a58f2f 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -161,6 +161,8 @@ struct drive_source {
/* Optional username (may be NULL if not specified). */
char *username;
+ /* Optional secret (may be NULL if not specified). */
+ char *secret;
};
struct drive {
diff --git a/src/guestfs.pod b/src/guestfs.pod
index ee9cc2a..99374c2 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -652,11 +652,14 @@ L</guestfs_add_drive_opts> like this:
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "rbd",
GUESTFS_ADD_DRIVE_OPTS_SERVER, servers,
+ GUESTFS_ADD_DRIVE_OPTS_USERNAME, "rbduser",
+ GUESTFS_ADD_DRIVE_OPTS_SECRET,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
-1);
C<servers> (the C<server> parameter) is a list of one or more Ceph
servers. The server string is documented in
-L</guestfs_add_drive_opts>.
+L</guestfs_add_drive_opts>. The C<username> and C<secret> parameters
are
+also optional, and if not given, then no authentication will be used.
=head3 GLUSTER
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index c2bd81c..e33ddc6 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -1144,6 +1144,9 @@ construct_libvirt_xml_disk (guestfs_h *g,
XMLERROR (-1,
xmlTextWriterWriteAttribute (xo, BAD_CAST "username",
BAD_CAST drv_priv->real_src.username));
+ /* TODO: write the drive secret, after first storing it separately
+ * in libvirt
+ */
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
}
--
1.7.9.5