On Thu, Oct 08, 2015 at 17:25:53 +0530, Prasanna Kumar Kalever
wrote:
> This patch adds support for gluster specific JSON parser functionality
This patch needs to go in before we actually add the support, so as 1/1
of this series.
>
> This will help in parsing the backing store which uses JSON syntax and
> update
> the meta-data in the domain specific objects while taking snapshots which
> inturn
> helps in successful creation/updation of backing store information in
> domain xml
>
> Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
> ---
> src/util/virstoragefile.c | 130
> ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 130 insertions(+)
>
> diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
> index 2aa1d90..c122d3a 100644
> --- a/src/util/virstoragefile.c
> +++ b/src/util/virstoragefile.c
> @@ -41,6 +41,7 @@
> #include "virstring.h"
> #include "virutil.h"
> #include "viruri.h"
> +#include "virjson.h"
> #include "dirname.h"
> #include "virbuffer.h"
>
> @@ -2124,6 +2125,132 @@
> virStorageSourceNewFromBackingRelative(virStorageSourcePtr parent,
> goto cleanup;
> }
>
> +static int
> +virStorageSourceParseBackingJSON(virStorageSourcePtr src,
> + const char *path)
Weird alignment. Also you probably missed a part in my previous review
where I'd requested that this is put into the qemu specific code rather
than the generic util code since this is too qemu specific.
On the other hand, it might be worth checking where the backing chain
functions are used and just move all the backing store parsers into qemu
code as probably all of it is very qemu specific too.
> +{
> +#if WITH_STORAGE_GLUSTER
Either the whole function is in the #if block and you have an else block
with a stub function that reports an error, or preferred is to have this
even if we don't compile with gluster since this doesn't use any gluster
api so it can be compiled always
> +
> + virJSONValuePtr json = NULL;
> + virJSONValuePtr file = NULL;
> + virJSONValuePtr volfile_server = NULL;
> + char *transport = NULL;
> + int port = 0;
> + size_t i = 0;
> +
> + /* The string may look like:
> + * json:{ file: { driver:"gluster", volname:"testvol",
> image-path:"/a.img",
> + * volfile-servers :[ {server:"1.2.3.4", port:24007,
transport:"tcp"}
> ,
> + * {server:"5.6.7.8", port:24008,
> transport:"rdma"},
> + * {}, ... ] }, driver:"qcow2" }
> + */
> +
> + json = virJSONValueFromString(path+strlen("json:"));
> +
> + if (virJSONValueObjectHasKey(json, "driver")) {
> + if (!(src->format = virStorageFileFormatTypeFromString(
> + virJSONValueObjectGetString(json, "driver")))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get Format type of key 'driver' from
> JSON"));
virStorageFileFormatTypeFromString returns -1 if it fails to parse the
format type. Format '0' might be valid.
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(json, "file")) {
> + if (!(file = virJSONValueObjectGet(json, "file"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unbale to get Object from key 'file'"));
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(file, "driver")) {
> + if (!(src->protocol = virStorageNetProtocolTypeFromString(
> + virJSONValueObjectGetString(file, "driver")))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get Protocol type of key 'driver'
from
> JSON"));
Same comment as above for usage of the enum->string helpers.
Additionally the assumption that 'drive' will contain something that can
be used successfully with virStorageNetProtocolTypeFromString is wrong.
The json syntax can be used with all the remote or local files and the
virStorageNetProtocolTypeFromString certainly won't recognize local
files. That would result in a rather unhelpful error.
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(file, "volname")) {
This uses the old naming in qemu, that I've pointed out is not what
should be done in qemu. Additionally my comment about the naming was
done prior to this submission.
I'd suggest you tackle the qemu part first at this point.
Additionally this is a gluster specific field. And the parser at least
according to the function name sounds rather generic. I think this would
badly fail on anything non'gluster.
> + if (!(src->volume = (char *) virJSONValueObjectGetString(file,
> + "volname"))) {
You are extracting a string but you are not copying it.
virJSONValueObjectGetString returns just the pointer to the string in
the json data structure. This either crashes or leaks the json array
so that it accidentally remains valid. Did you actually test it?
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unbale to get String from key
'volname'"));
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(file, "image-path")) {
Again ... old field name.
> + if (!(src->path = (char *) virJSONValueObjectGetString(file,
> + "image-path"))) {
And wrong extraction of it.
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get String from key
'image-path'"));
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(file, "volfile-servers")) {
Wrong field name. This is also the reason why "volfile-servers" is a
terrible name. Any other protocol that certainly won't call it's server
field volfile-servers. We would need to add a different code path here.
Gluster isn't the only storage technology on the planet, so this code
needs to be extensible
Peter, I have send the patch to qemu just before with the naming conventions
yourself and Kevin suggested on v5 patch of qemu.
But before sending this patch qemu v5 patch-set have the older naming conventions,
so obviously if somebody want to test this patch which depends on qemu patch,
the naming conventions must be as qemu v5 path-set, so knowingly I followed the
older naming conventions. I hope you understand that part.
Anyways I know this patch-set is not the final one that goes-in Coz of some of
holes in my understanding of being very new user to libvirt, I shall update
this patch with qemu v6 naming conventions very soon.
I shall also consider the valuable points you mention in this mail.
Thank you.
> + if (!(src->nhosts =
> virJSONValueArraySize(virJSONValueObjectGet(file,
> + "volfile-servers")))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get Size of Array of key
> 'volfile-servers'"));
> + goto error;
> + }
> + }
> +
> + /* null-terminated list */
Why? We store the countof elements.
> + if (VIR_ALLOC_N(src->hosts, src->nhosts + 1) < 0)
> + goto error;
> +
> + for (i = 0; i < src->nhosts; i++) {
> + volfile_server =
> virJSONValueArrayGet(virJSONValueObjectGetArray(file,
> + "volfile-servers"), i);
Wrong name. Weird alignment.
> +
> + if (virJSONValueObjectHasKey(volfile_server, "server")) {
Wrong field name.
> + if (VIR_STRDUP(src->hosts[i].name,
> + virJSONValueObjectGetString(volfile_server,
> "server")) < 0) {
Wow, here you copy the string. Didn't that seem suspicious compared to
the avoce usage?
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get String from key
'server'"));
You've validated that "server" key exists, so the only error here is if
VIR_STRDUP fails. VIR_STRDUP also reports it's own errors.
> + goto error;
> + }
> + }
> +
> + if (virJSONValueObjectHasKey(volfile_server, "port")) {
> + if (virJSONValueObjectGetNumberInt(volfile_server, "port",
> &port) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get NumberInt from key
'port'"));
> + goto error;
> + }
> + if (virAsprintf(&src->hosts[i].port, "%d", port) <
0)
> + goto error;
> + }
> +
> + if (virJSONValueObjectHasKey(volfile_server, "transport")) {
> + if (VIR_STRDUP(transport,
> virJSONValueObjectGetString(volfile_server,
> + "transport")) < 0) {
Here you duplicate the string containing the transport ....
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Unable to get String from key
'transport'"));
> + goto error;
> + }
> + src->hosts[i].transport =
> virStorageNetHostTransportTypeFromString(transport);
Convert it without actually checking that the conversion was
successful...
> + VIR_FREE(transport);
And free it. That's a waste since you didn't use the 'transport' string
out of the context here. Seems like you should use approach like this
above but certainly not here.
> + }
> + }
Oh right, this leaks all the stuff on success, so that's why it doesn't
crash. That's obviously not right.
> +
> + return 0;
> +
> + error:
> + VIR_FREE(transport);
> + virJSONValueFree(volfile_server);
> + virJSONValueFree(file);
> + virJSONValueFree(json);
> +
> +#endif /* WITH_STORAGE_GLUSTER */
You'd get compilation errors if WITH_STORAGE_GLUSTER is not enabled due
to unused variables.
> +
> + return -1;
> +}
>
> static int
> virStorageSourceParseBackingURI(virStorageSourcePtr src,
Peter