-----BEGIN PGP SIGNATURE-----

iQIcBAABAgAGBQJY3wERAAoJEL2+eyfA3jBXw0cP+wUG0ygMCepHtAb1R2JOzFal
 PG9k3bxEO0bPiHxKu8N1Iph5Mi3+d3KX7nXv0cipgboUn2wMk064Giz39XjvN9ZH
 CF54wXua76bCTbAD7ZGOrZMx2WzexAwNoskknxaWKI65fGXHzZTlSdn0/S/mUgvx
 5PmxQeD/1qJ2IvBqymk/zIf8uR6t8iJKawchY0seXBYNZZqhC/6OzGL0sCOx2BiD
 b0KIrRCb8nwqNQcxTylldxMDvKS2C2vy8upuiuY4Onp76TXglaMNOLt/dGLGIMVd
 Ux7tiIQM+Sq6WZDrUqOZwULAY7sujJXCTGxDc8jCfb7LooK8PP5MszSotvabkH9T
 drPLfi4WBCiohdkpmVAAp325nIUvnLBDRkdsSxkyDMVQ3RXUchIUK6Ta6n1U15fr
 L8Ls/jUQankf/1NBJ5yIkTCT0L73jb2vjtdQJlZHV9hHCspTDNosrHU6O5I03BGE
 4BMtDp3emrITxSOjpNz6XRxNiIq2x69R0wiAJbh8ZtEFCTI5K6Sr3JOPaWv7swYe
 mblYePVKcohQlHmKouiV0I8Cyuz+lLIYBO2Lp3wu1AOL1WwmpfmHkCOB/OzGkzhW
 UUnpWo6SXt8pbVSrzWqfg2RC1p/KASSAqo1ZQMFi9jaqksiu+UdOE32uWjQgBOr0
 BMKD5LzQdm0WU0/Bjh6X
 =4Xoj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cody/tags/block-pull-request' into staging

# gpg: Signature made Sat 01 Apr 2017 02:23:29 BST
# gpg:                using RSA key 0xBDBE7B27C0DE3057
# gpg: Good signature from "Jeffrey Cody <jcody@redhat.com>"
# gpg:                 aka "Jeffrey Cody <jeff@codyprime.org>"
# gpg:                 aka "Jeffrey Cody <codyprime@gmail.com>"
# Primary key fingerprint: 9957 4B4D 3474 90E7 9D98  D624 BDBE 7B27 C0DE 3057

* remotes/cody/tags/block-pull-request:
  block/curl: Check protocol prefix
  qapi/curl: Extend and fix blockdev-add schema
  rbd: Fix regression in legacy key/values containing escaped :

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2017-04-03 10:09:58 +01:00
commit 6954cdc070
3 changed files with 146 additions and 50 deletions

View File

@ -659,6 +659,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
const char *cookie;
double d;
const char *secretid;
const char *protocol_delimiter;
static int inited = 0;
@ -700,6 +701,15 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
goto out_noclean;
}
if (!strstart(file, bs->drv->protocol_name, &protocol_delimiter) ||
!strstart(protocol_delimiter, "://", NULL))
{
error_setg(errp, "%s curl driver cannot handle the URL '%s' (does not "
"start with '%s://')", bs->drv->protocol_name, file,
bs->drv->protocol_name);
goto out_noclean;
}
s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);

View File

@ -20,6 +20,7 @@
#include "crypto/secret.h"
#include "qemu/cutils.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp/qjson.h"
/*
* When specifying the image filename use:
@ -135,18 +136,16 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
Error **errp)
{
const char *start;
char *p, *buf, *keypairs;
char *p, *buf;
QList *keypairs = NULL;
char *found_str;
size_t max_keypair_size;
if (!strstart(filename, "rbd:", &start)) {
error_setg(errp, "File name must start with 'rbd:'");
return;
}
max_keypair_size = strlen(start) + 1;
buf = g_strdup(start);
keypairs = g_malloc0(max_keypair_size);
p = buf;
found_str = qemu_rbd_next_tok(p, '/', &p);
@ -194,33 +193,30 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
} else if (!strcmp(name, "id")) {
qdict_put(options, "user" , qstring_from_str(value));
} else {
/* FIXME: This is pretty ugly, and not the right way to do this.
* These should be contained in a structure, and then
* passed explicitly as individual key/value pairs to
* rados. Consider this legacy code that needs to be
* updated. */
char *tmp = g_malloc0(max_keypair_size);
/* only use a delimiter if it is not the first keypair found */
/* These are sets of unknown key/value pairs we'll pass along
* to ceph */
if (keypairs[0]) {
snprintf(tmp, max_keypair_size, ":%s=%s", name, value);
pstrcat(keypairs, max_keypair_size, tmp);
} else {
snprintf(keypairs, max_keypair_size, "%s=%s", name, value);
/*
* We pass these internally to qemu_rbd_set_keypairs(), so
* we can get away with the simpler list of [ "key1",
* "value1", "key2", "value2" ] rather than a raw dict
* { "key1": "value1", "key2": "value2" } where we can't
* guarantee order, or even a more correct but complex
* [ { "key1": "value1" }, { "key2": "value2" } ]
*/
if (!keypairs) {
keypairs = qlist_new();
}
g_free(tmp);
qlist_append(keypairs, qstring_from_str(name));
qlist_append(keypairs, qstring_from_str(value));
}
}
if (keypairs[0]) {
qdict_put(options, "=keyvalue-pairs", qstring_from_str(keypairs));
if (keypairs) {
qdict_put(options, "=keyvalue-pairs",
qobject_to_json(QOBJECT(keypairs)));
}
done:
g_free(buf);
g_free(keypairs);
QDECREF(keypairs);
return;
}
@ -244,36 +240,41 @@ static int qemu_rbd_set_auth(rados_t cluster, const char *secretid,
return 0;
}
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs,
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
Error **errp)
{
char *p, *buf;
char *name;
char *value;
QList *keypairs;
QString *name;
QString *value;
const char *key;
size_t remaining;
int ret = 0;
buf = g_strdup(keypairs);
p = buf;
if (!keypairs_json) {
return ret;
}
keypairs = qobject_to_qlist(qobject_from_json(keypairs_json,
&error_abort));
remaining = qlist_size(keypairs) / 2;
assert(remaining);
while (p) {
name = qemu_rbd_next_tok(p, '=', &p);
if (!p) {
error_setg(errp, "conf option %s has no value", name);
ret = -EINVAL;
break;
}
while (remaining--) {
name = qobject_to_qstring(qlist_pop(keypairs));
value = qobject_to_qstring(qlist_pop(keypairs));
assert(name && value);
key = qstring_get_str(name);
value = qemu_rbd_next_tok(p, ':', &p);
ret = rados_conf_set(cluster, name, value);
ret = rados_conf_set(cluster, key, qstring_get_str(value));
QDECREF(name);
QDECREF(value);
if (ret < 0) {
error_setg_errno(errp, -ret, "invalid conf option %s", name);
error_setg_errno(errp, -ret, "invalid conf option %s", key);
ret = -EINVAL;
break;
}
}
g_free(buf);
QDECREF(keypairs);
return ret;
}

View File

@ -2737,16 +2737,101 @@
'*debug': 'int' } }
##
# @BlockdevOptionsCurl:
# @BlockdevOptionsCurlBase:
#
# Driver specific block device options for the curl backend.
# Driver specific block device options shared by all protocols supported by the
# curl backend.
#
# @filename: path to the image file
# @url: URL of the image file
#
# @readahead: Size of the read-ahead cache; must be a multiple of
# 512 (defaults to 256 kB)
#
# @timeout: Timeout for connections, in seconds (defaults to 5)
#
# @username: Username for authentication (defaults to none)
#
# @password-secret: ID of a QCryptoSecret object providing a password
# for authentication (defaults to no password)
#
# @proxy-username: Username for proxy authentication (defaults to none)
#
# @proxy-password-secret: ID of a QCryptoSecret object providing a password
# for proxy authentication (defaults to no password)
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsCurl',
'data': { 'filename': 'str' } }
{ 'struct': 'BlockdevOptionsCurlBase',
'data': { 'url': 'str',
'*readahead': 'int',
'*timeout': 'int',
'*username': 'str',
'*password-secret': 'str',
'*proxy-username': 'str',
'*proxy-password-secret': 'str' } }
##
# @BlockdevOptionsCurlHttp:
#
# Driver specific block device options for HTTP connections over the curl
# backend. URLs must start with "http://".
#
# @cookie: List of cookies to set; format is
# "name1=content1; name2=content2;" as explained by
# CURLOPT_COOKIE(3). Defaults to no cookies.
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsCurlHttp',
'base': 'BlockdevOptionsCurlBase',
'data': { '*cookie': 'str' } }
##
# @BlockdevOptionsCurlHttps:
#
# Driver specific block device options for HTTPS connections over the curl
# backend. URLs must start with "https://".
#
# @cookie: List of cookies to set; format is
# "name1=content1; name2=content2;" as explained by
# CURLOPT_COOKIE(3). Defaults to no cookies.
#
# @sslverify: Whether to verify the SSL certificate's validity (defaults to
# true)
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsCurlHttps',
'base': 'BlockdevOptionsCurlBase',
'data': { '*cookie': 'str',
'*sslverify': 'bool' } }
##
# @BlockdevOptionsCurlFtp:
#
# Driver specific block device options for FTP connections over the curl
# backend. URLs must start with "ftp://".
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsCurlFtp',
'base': 'BlockdevOptionsCurlBase',
'data': { } }
##
# @BlockdevOptionsCurlFtps:
#
# Driver specific block device options for FTPS connections over the curl
# backend. URLs must start with "ftps://".
#
# @sslverify: Whether to verify the SSL certificate's validity (defaults to
# true)
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsCurlFtps',
'base': 'BlockdevOptionsCurlBase',
'data': { '*sslverify': 'bool' } }
##
# @BlockdevOptionsNbd:
@ -2815,13 +2900,13 @@
'cloop': 'BlockdevOptionsGenericFormat',
'dmg': 'BlockdevOptionsGenericFormat',
'file': 'BlockdevOptionsFile',
'ftp': 'BlockdevOptionsCurl',
'ftps': 'BlockdevOptionsCurl',
'ftp': 'BlockdevOptionsCurlFtp',
'ftps': 'BlockdevOptionsCurlFtps',
'gluster': 'BlockdevOptionsGluster',
'host_cdrom': 'BlockdevOptionsFile',
'host_device':'BlockdevOptionsFile',
'http': 'BlockdevOptionsCurl',
'https': 'BlockdevOptionsCurl',
'http': 'BlockdevOptionsCurlHttp',
'https': 'BlockdevOptionsCurlHttps',
'iscsi': 'BlockdevOptionsIscsi',
'luks': 'BlockdevOptionsLUKS',
'nbd': 'BlockdevOptionsNbd',