Skip to contentSkip to conversation

libxl: support json for pretty printing objects

PATCH In review Ian Campbell 2 participants 7 messages Oct 7, 2011 – Oct 17, 2011

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 libxl: support json for pretty printing objects

Now that Anthony's QMP series is in we can build upon the use of YAJL to add support for pretty printing libxl objects as JSON.

Also includes a user in xl (to print disks on dry run) and an associated fix to the check-xl-disk-parse test script.

This is the second posting. A subset of the patches have been applied so I have rebased. I have also addressed most of Ian J's review comments on "libxl: IDL: autogenerate functions to produce JSON from libxl data structures":
- wrap python code to 80 columns
- fixup quoting (although I had to add another case in \"%s=%#x\" because "%s=%#x" was confusing emacs' syntax highlighting due to the # being treated as a comment and hiding the closing ".
- remove leftover cruft
- added libxl__yagl_gen_enum helper
- autogenerate *_gen_json prototypes for builtins instead of handcoding them.

I didn't address the cpuid related comments.

I switched to using "xl" not "/usr/sbin/xl" in that patch.

#1 lore raw

PATCH v2 1/1 libxl: IDL: autogenerate functions to produce JSON from libxl data structures

# HG changeset patch
# User Ian Campbell <[email protected]>
# Date 1317981945 -3600
# Node ID 75a0a29cccbfce75ba3087cdaf53adfd1b377a11
# Parent 43b99763284fa639e47dbeb9245f0ebd1d4f2dad
libxl: IDL: autogenerate functions to produce JSON from libxl data structures.

Two functions are provided. TYPE_gen_json exposes an interface which is compatible with the YAGL generator infrastructure. TYPE_to_string uses this to produce a pretty printed string.

The TYPE_gen_json functions are defined in a new header libxl_json.h which is not exposed via libxl.h due to the use of YAGL datatypes to avoid poluting the namespace us libxl users which don't use the library themselves. If a libxl user is interested in integrating at the YAGL level then it should #include this file itself.

Also update testidl to generate a random version of each IDL datastructure and convert it to JSON. Unfortunately this requires a libxl_ctx and therefore the test must be run on a Xen system now.

tools/libxl/Makefile +6 -3
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/Makefile
@@ -84,14 +84,17 @@ _libxl_paths.h: genpath
 libxl_paths.c: _libxl_paths.h
 
 libxl.h: _libxl_types.h
+libxl_json.h: _libxl_types_json.h
 libxl_internal.h: _libxl_types_internal.h
+libxl_internal_json.h: _libxl_types_internal_json.h
 
 $(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): libxl.h
 $(LIBXL_OBJS): libxl_internal.h
 
-_libxl_type%.h _libxl_type%.c: libxl_type%.idl gentypes.py libxltypes.py
-	$(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h __libxl_type$*.c
+_libxl_type%.h _libxl_type%_json.h _libxl_type%.c: libxl_type%.idl gentypes.py libxltypes.py
+	$(PYTHON) gentypes.py libxl_type$*.idl __libxl_type$*.h __libxl_type$*_json.h __libxl_type$*.c
 	$(call move-if-changed,__libxl_type$*.h,_libxl_type$*.h)
+	$(call move-if-changed,__libxl_type$*_json.h,_libxl_type$*_json.h)
 	$(call move-if-changed,__libxl_type$*.c,_libxl_type$*.c)
 
 libxenlight.so: libxenlight.so.$(MAJOR)
@@ -140,7 +143,7 @@ install: all
 	ln -sf libxlutil.so.$(XLUMAJOR).$(XLUMINOR) $(DESTDIR)$(LIBDIR)/libxlutil.so.$(XLUMAJOR)
 	ln -sf libxlutil.so.$(XLUMAJOR) $(DESTDIR)$(LIBDIR)/libxlutil.so
 	$(INSTALL_DATA) libxlutil.a $(DESTDIR)$(LIBDIR)
-	$(INSTALL_DATA) libxl.h _libxl_types.h libxl_utils.h libxl_uuid.h $(DESTDIR)$(INCLUDEDIR)
+	$(INSTALL_DATA) libxl.h libxl_json.h _libxl_types.h _libxl_types_json.h libxl_utils.h libxl_uuid.h $(DESTDIR)$(INCLUDEDIR)
 	$(INSTALL_DATA) bash-completion $(DESTDIR)$(BASH_COMPLETION_DIR)/xl.sh
 
 .PHONY: clean
tools/libxl/gentest.py +245 -8

294 lines not on this page · raw message

tools/libxl/gentypes.py +96 -6

146 lines not on this page · raw message

tools/libxl/idl.txt +9 -0
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/idl.txt
@@ -49,6 +49,15 @@ Type.autogenerate_destructor: (default: 
  Indicates if the above named Type.destructor_fn should be
  autogenerated.
 
+Type.json_fn: (default: typename + "_gen_json" or None if type == None)
+
+ The name of the C function which will generate a YAJL data structure
+ representing this type.
+
+Type.autogenerate_json: (default: True)
+
+ Indicates if the above named Type.json_fn should be autogenerated.
+
 Other simple type-Classes
 -------------------------
 
tools/libxl/libxl.h +2 -2
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl.h
@@ -199,10 +199,10 @@ typedef struct {
     int v;
 } libxl_enum_string_table;
 
+typedef struct libxl__ctx libxl_ctx;
+
 #include "_libxl_types.h"
 
-typedef struct libxl__ctx libxl_ctx;
-
 const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx);
 
 typedef struct {
tools/libxl/libxl_internal.h +11 -0
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_internal.h
@@ -35,7 +35,9 @@
 
 #include "flexarray.h"
 #include "libxl_utils.h"
+
 #include "_libxl_types_internal.h"
+#include "libxl_json.h"
 
 #define LIBXL_DESTROY_TIMEOUT 10
 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10
@@ -362,6 +364,14 @@ _hidden char *libxl__cpupoolid_to_name(l
 _hidden int libxl__enum_from_string(const libxl_enum_string_table *t,
                                     const char *s, int *e);
 
+_hidden yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str);
+
+_hidden yajl_gen_status libxl__string_gen_json(yajl_gen hand, const char *p);
+
+typedef yajl_gen_status (*libxl__gen_json_callback)(yajl_gen hand, void *);
+_hidden char *libxl__object_to_json(libxl_ctx *ctx, const char *type,
+                                    libxl__gen_json_callback gen, void *p);
+
   /* holds the CPUID response for a single CPUID leaf
    * input contains the value of the EAX and ECX register,
    * and each policy string contains a filter to apply to
@@ -447,6 +457,7 @@ _hidden int libxl__qmp_initializations(l
 #include <yajl/yajl_gen.h>
 
 _hidden yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str);
+_hidden yajl_gen_status libxl__yajl_gen_enum(yajl_gen hand, const char *str);
 
 typedef enum {
     JSON_ERROR,
tools/libxl/libxl_json.c +276 -0

291 lines not on this page · raw message

tools/libxl/libxl_json.h new file +23 -0
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_json.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011      Citrix Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#ifndef LIBXL_JSON_H
+#define LIBXL_JSON_H
+
+#include <yajl/yajl_gen.h>
+
+#include <_libxl_types_json.h>
+#include <_libxl_types_internal_json.h>
+
+#endif /* LIBXL_JSON_H */
tools/libxl/libxl_types.idl +2 -2
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxl_types.idl
@@ -5,7 +5,7 @@
 
 namespace("libxl_")
 
-libxl_domid = Builtin("domid")
+libxl_domid = Builtin("domid", json_fn = "yajl_gen_integer", autogenerate_json = False)
 libxl_uuid = Builtin("uuid", passby=PASS_BY_REFERENCE)
 libxl_mac = Builtin("mac", passby=PASS_BY_REFERENCE)
 libxl_cpumap = Builtin("cpumap", destructor_fn="libxl_cpumap_destroy", passby=PASS_BY_REFERENCE)
@@ -16,7 +16,7 @@ libxl_string_list = Builtin("string_list
 libxl_key_value_list = Builtin("key_value_list", destructor_fn="libxl_key_value_list_destroy", passby=PASS_BY_REFERENCE)
 libxl_file_reference = Builtin("file_reference", destructor_fn="libxl_file_reference_destroy", passby=PASS_BY_REFERENCE)
 
-libxl_hwcap = Builtin("hwcap")
+libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE)
 
 #
 # Constants / Enumerations
tools/libxl/libxltypes.py +18 -2
diff -r 43b99763284f -r 75a0a29cccbf tools/libxl/libxltypes.py
@@ -50,6 +50,13 @@ class Type(object):
 
         self.autogenerate_destructor = kwargs.setdefault('autogenerate_destructor', True)
 
+        if self.typename is not None:
+            self.json_fn = kwargs.setdefault('json_fn', self.typename + "_gen_json")
+        else:
+            self.json_fn = kwargs.setdefault('json_fn', None)
+
+        self.autogenerate_json = kwargs.setdefault('autogenerate_json', True)
+
     def marshal_in(self):
         return self.dir in [DIR_IN, DIR_BOTH]
     def marshal_out(self):
@@ -83,6 +90,7 @@ class Builtin(Type):
     def __init__(self, typename, **kwargs):
         kwargs.setdefault('destructor_fn', None)
         kwargs.setdefault('autogenerate_destructor', False)
+        kwargs.setdefault('autogenerate_json', False)
         Type.__init__(self, typename, **kwargs)
 
 class Number(Builtin):
@@ -90,6 +98,7 @@ class Number(Builtin):
         kwargs.setdefault('namespace', None)
         kwargs.setdefault('destructor_fn', None)
         kwargs.setdefault('signed', False)
+        kwargs.setdefault('json_fn', "yajl_gen_integer")
         self.signed = kwargs['signed']
         Builtin.__init__(self, ctype, **kwargs)
 
@@ -163,6 +172,8 @@ class Aggregate(Type):
                 comment = None
             else:
                 n,t,const,comment = f
+            if n is None:
+                raise ValueError
             self.fields.append(Field(t,n,const=const,comment=comment))
 
     # Returns a tuple (stem, field-expr)
@@ -220,7 +231,10 @@ class KeyedUnion(Aggregate):
 #
 
 void = Builtin("void *", namespace = None)
-bool = Builtin("bool", namespace = None)
+bool = Builtin("bool", namespace = None,
+               json_fn = "yajl_gen_bool",
+               autogenerate_json = False)
+
 size_t = Number("size_t", namespace = None)
 
 integer = Number("int", namespace = None, signed = True)
@@ -230,7 +244,9 @@ uint16 = UInt(16)
 uint32 = UInt(32)
 uint64 = UInt(64)
 
-string = Builtin("char *", namespace = None, destructor_fn = "free")
+string = Builtin("char *", namespace = None, destructor_fn = "free",
+                 json_fn = "libxl__string_gen_json",
+                 autogenerate_json = False)
 
 class OrderedDict(dict):
     """A dictionary which remembers insertion order.
#2 lore raw

PATCH v2 1/1 xl: allow check-xl-disk-parse to run against installed xl as well as build dir

In reply to Ian Campbell

# HG changeset patch
# User Ian Campbell <[email protected]>
# Date 1317981947 -3600
# Node ID 347c7631c123af9abdc5d6dbe10ea32cf5804aab
# Parent 75a0a29cccbfce75ba3087cdaf53adfd1b377a11
xl: allow check-xl-disk-parse to run against installed xl as well as build dir

I can't run from the current directory since my build box isn't running Xen so if ./xl doesn't exist use the installed version on the assumption that I've copied the script to a test host.

I think running from the build dir needs the blktap2 libraries, so update LD_LIBRARY_PATH as appropriate.

tools/libxl/check-xl-disk-parse +8 -2
diff -r 75a0a29cccbf -r 347c7631c123 tools/libxl/check-xl-disk-parse
@@ -2,6 +2,13 @@
 
 set -e
 
+if [ -x ./xl ] ; then
+    export LD_LIBRARY_PATH=.:../libxc:../xenstore:../blktap2/control
+    XL=./xl
+else
+    XL=xl
+fi
+
 fprefix=tmp.check-xl-disk-parse
 
 expected () {
@@ -14,8 +21,7 @@ one () {
     expected_rc=$1; shift
     printf "test case %s...\n" "$*"
     set +e
-    LD_LIBRARY_PATH=.:../libxc:../xenstore \
-        ./xl -N block-attach 0 "$@" </dev/null >$fprefix.actual 2>/dev/null
+    ${XL} -N block-attach 0 "$@" </dev/null >$fprefix.actual 2>/dev/null
     actual_rc=$?
     diff -u $fprefix.expected $fprefix.actual
     diff_rc=$?
#3 lore raw

PATCH v2 1/1 xl: use libxl_device_disk_to_json to pretty print disk configuration

In reply to Ian Campbell

# HG changeset patch
# User Ian Campbell <[email protected]>
# Date 1317982001 -3600
# Node ID 7dc93b06164542f06958a181c4747770a5552457
# Parent 347c7631c123af9abdc5d6dbe10ea32cf5804aab
xl: use libxl_device_disk_to_json to pretty print disk configuration

tools/libxl/check-xl-disk-parse +24 -18
diff -r 347c7631c123 -r 7dc93b061645 tools/libxl/check-xl-disk-parse
@@ -51,15 +51,18 @@ expected </dev/null
 one $e foo
 
 expected <<END
-disk.backend_domid = 0
-disk.pdev_path =     /dev/vg/guest-volume
-disk.vdev =          hda
-disk.backend =       0
-disk.format =        4
-disk.script =        (null)
-disk.removable =     0
-disk.readwrite =     1
-disk.is_cdrom =      0
+disk: {
+    "backend_domid": 0,
+    "pdev_path": "/dev/vg/guest-volume",
+    "vdev": "hda",
+    "backend": "unknown",
+    "format": "raw",
+    "script": null,
+    "removable": 0,
+    "readwrite": 1,
+    "is_cdrom": 0
+}
+
 END
 one 0 /dev/vg/guest-volume,,hda
 one 0 /dev/vg/guest-volume,raw,hda,rw
@@ -68,15 +71,18 @@ one 0  format=raw  vdev=hda  access=rw  
 one 0 raw:/dev/vg/guest-volume,hda,w
 
 expected <<END
-disk.backend_domid = 0
-disk.pdev_path =     /root/image.iso
-disk.vdev =          hdc
-disk.backend =       0
-disk.format =        4
-disk.script =        (null)
-disk.removable =     1
-disk.readwrite =     0
-disk.is_cdrom =      1
+disk: {
+    "backend_domid": 0,
+    "pdev_path": "/root/image.iso",
+    "vdev": "hdc",
+    "backend": "unknown",
+    "format": "raw",
+    "script": null,
+    "removable": 1,
+    "readwrite": 0,
+    "is_cdrom": 1
+}
+
 END
 one 0 /root/image.iso,,hdc,cdrom
 one 0 /root/image.iso,,hdc,,cdrom
tools/libxl/xl_cmdimpl.c +3 -11
diff -r 347c7631c123 -r 7dc93b061645 tools/libxl/xl_cmdimpl.c
@@ -4112,17 +4112,9 @@ int main_blockattach(int argc, char **ar
     disk.backend_domid = be_domid;
 
     if (dryrun_only) {
-        /* fixme: this should be generated from the idl */
-        /* fixme: enums (backend, format) should be converted to strings */
-        printf("disk.backend_domid = %"PRIx32"\n", disk.backend_domid);
-        printf("disk.pdev_path =     %s\n",        disk.pdev_path);
-        printf("disk.vdev =          %s\n",        disk.vdev);
-        printf("disk.backend =       %d\n",        disk.backend);
-        printf("disk.format =        %d\n",        disk.format);
-        printf("disk.script =        %s\n",        disk.script);
-        printf("disk.removable =     %d\n",        disk.removable);
-        printf("disk.readwrite =     %d\n",        disk.readwrite);
-        printf("disk.is_cdrom =      %d\n",        disk.is_cdrom);
+        char *json = libxl_device_disk_to_json(ctx, &disk);
+        printf("disk: %s\n", json);
+        free(json);
         if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(-1); }
         return 0;
     }
#4 lore raw

PATCH v2 1/1 libxl: add a test case for correct parsing of disk "backendtype" field

In reply to Ian Campbell

# HG changeset patch
# User Ian Campbell <[email protected]>
# Date 1317983222 -3600
# Node ID e530b4b35d3872d93013daa4233cc467a89a1bac
# Parent 7dc93b06164542f06958a181c4747770a5552457
libxl: add a test case for correct parsing of disk "backendtype" field

tools/libxl/check-xl-disk-parse +16 -0
diff -r 7dc93b061645 -r e530b4b35d38 tools/libxl/check-xl-disk-parse
@@ -91,4 +91,20 @@ one 0 "format=raw, vdev=hdc, access=ro, 
 one 0  format=raw  vdev=hdc  access=ro  devtype=cdrom  target=/root/image.iso
 one 0 raw:/root/image.iso,hdc:cdrom,ro
 
+expected <<EOF
+disk: {
+    "backend_domid": 0,
+    "pdev_path": "/dev/vg/guest-volume",
+    "vdev": "xvdb",
+    "backend": "phy",
+    "format": "raw",
+    "script": null,
+    "removable": 0,
+    "readwrite": 1,
+    "is_cdrom": 0
+}
+
+EOF
+one 0 backendtype=phy,vdev=xvdb,access=w,target=/dev/vg/guest-volume
+
 complete
#5 lore raw
In reply to Ian Campbell
Quoted 5 lines · Ian Campbell

Now that Anthony's QMP series is in we can build upon the use of YAJL to add support for pretty printing libxl objects as JSON.

Also includes a user in xl (to print disks on dry run) and an associated fix to the check-xl-disk-parse test script.

In my V1 posting of this series I also included "libxl: probe disk backend type in libxl_device_disk_add" but forgot it in the repost, so here is patch 5/4:

# HG changeset patch
# User Ian Campbell <[email protected]> # Date 1318498260 -3600
# Node ID 29bd271877873f4a38217de89f8f4f74405496b5 # Parent 98cb420b606bf69e3e3177ebe8b16b529c5ed0ed
libxl: probe disk backend type in libxl_device_disk_add

Without this "xl block-attach" does not work. On create do_domain_create already catches this.

tools/libxl/libxl.c +3 -0
diff -r 98cb420b606b -r 29bd27187787 tools/libxl/libxl.c
@@ -929,6 +929,9 @@ int libxl_device_disk_add(libxl_ctx *ctx
     rc = libxl__device_disk_set_backend(&gc, disk);
     if (rc) goto out;
 
+    rc = libxl__device_disk_set_backend(&gc, disk);
+    if (rc) goto out;
+
     front = flexarray_make(16, 1);
     if (!front) {
         rc = ERROR_NOMEM;
#6 lore raw

Ian Campbell writes ("[Xen-devel] Re: [PATCH 0 of 4 v2] libxl: support json for > In my V1 posting of this series I also included "libxl: probe disk

Quoted 2 lines

backend type in libxl_device_disk_add" but forgot it in the repost, so here is patch 5/4:

Thanks, acked and applied all 5.

Ian.