-----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>
This commit is contained in:
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; const char *cookie;
double d; double d;
const char *secretid; const char *secretid;
const char *protocol_delimiter;
static int inited = 0; static int inited = 0;
@ -700,6 +701,15 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
goto out_noclean; 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)); s->username = g_strdup(qemu_opt_get(opts, CURL_BLOCK_OPT_USERNAME));
secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET); secretid = qemu_opt_get(opts, CURL_BLOCK_OPT_PASSWORD_SECRET);

View File

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

View File

@ -2737,16 +2737,101 @@
'*debug': 'int' } } '*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 # Since: 2.9
## ##
{ 'struct': 'BlockdevOptionsCurl', { 'struct': 'BlockdevOptionsCurlBase',
'data': { 'filename': 'str' } } '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: # @BlockdevOptionsNbd:
@ -2815,13 +2900,13 @@
'cloop': 'BlockdevOptionsGenericFormat', 'cloop': 'BlockdevOptionsGenericFormat',
'dmg': 'BlockdevOptionsGenericFormat', 'dmg': 'BlockdevOptionsGenericFormat',
'file': 'BlockdevOptionsFile', 'file': 'BlockdevOptionsFile',
'ftp': 'BlockdevOptionsCurl', 'ftp': 'BlockdevOptionsCurlFtp',
'ftps': 'BlockdevOptionsCurl', 'ftps': 'BlockdevOptionsCurlFtps',
'gluster': 'BlockdevOptionsGluster', 'gluster': 'BlockdevOptionsGluster',
'host_cdrom': 'BlockdevOptionsFile', 'host_cdrom': 'BlockdevOptionsFile',
'host_device':'BlockdevOptionsFile', 'host_device':'BlockdevOptionsFile',
'http': 'BlockdevOptionsCurl', 'http': 'BlockdevOptionsCurlHttp',
'https': 'BlockdevOptionsCurl', 'https': 'BlockdevOptionsCurlHttps',
'iscsi': 'BlockdevOptionsIscsi', 'iscsi': 'BlockdevOptionsIscsi',
'luks': 'BlockdevOptionsLUKS', 'luks': 'BlockdevOptionsLUKS',
'nbd': 'BlockdevOptionsNbd', 'nbd': 'BlockdevOptionsNbd',