[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH V4 19/24] xl: introduce and use "xl-json" format



Originally xl verbatimly copies the domain config file in its user data
store. This patch adds the functionality to transform text domain config
file to JSON object and save that object in user data store.

Later patches will modify device hotplug commands and memory hotplug
commands to update the saved "xl-json" file as needed. In the end we
always have the up-to-date configurations of a domain saved in user data
store.

What this patch does:
1. add a mandatory flag to save protocol to indicate whether the saved
   config is a JSON object
2. register a new private data type "xl-json" in libxl.h
3. modify xl to save / load "xl-json" file where necessary

After this change xl supports both "xl" format and "xl-json" format.
A new flag "-j" is added to various commands, so that users can supply a
config file in JSON format.

Tests done so far (xl.{new,old} denotes xl with{,out} "xl_json"
support):

1. xl.new create then xl.new save, hexdump saved file: domain config
   saved in JSON format
2. xl.new create, xl.new save then xl.old restore: failed on mandatory
   flag check
3. xl.new create, xl.new save then xl.new restore: succeeded
4. xl.old create, xl.old save then xl.new restore: succeeded
5. xl.new create then local migrate, receiving end xl.new: succeeded
6. xl.old create then local migrate, receiving end xl.new: succeeded

The only drawback is that when restoring a domain, xl cannot
automatically spawn a vncviewer anymore. That's because that option is
part of domain_create info not domain configuration, thus it's not
saved in the JSON config. A warning is printed out and documentation
is updated.

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 docs/man/xl.cfg.pod.5     |    3 +-
 docs/man/xl.pod.1         |   21 +++
 tools/libxl/libxl.h       |    1 +
 tools/libxl/xl_cmdimpl.c  |  313 ++++++++++++++++++++++++++++++++++++---------
 tools/libxl/xl_cmdtable.c |   11 +-
 5 files changed, 285 insertions(+), 64 deletions(-)

diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
index c8ce6c1..e6c86b0 100644
--- a/docs/man/xl.cfg.pod.5
+++ b/docs/man/xl.cfg.pod.5
@@ -1114,7 +1114,8 @@ other VNC-related settings.  The default is to enable 
this.
 
 =item B<vncviewer=BOOLEAN>
 
-Automatically spawn a vncviewer when creating/restoring a guest.
+Automatically spawn a vncviewer when creating a guest. This option has
+no effect when restoring a guest and it might be removed in the future.
 
 =item B<vnclisten="ADDRESS[:DISPLAYNUM]">
 
diff --git a/docs/man/xl.pod.1 b/docs/man/xl.pod.1
index 30bd4bf..f1a1b9b 100644
--- a/docs/man/xl.pod.1
+++ b/docs/man/xl.pod.1
@@ -146,6 +146,11 @@ useful for determining issues with crashing domains and 
just as a
 general convenience since you often want to watch the
 domain boot.
 
+=item B<-j>
+
+The provided I<configfile> is in JSON format. Cannot be used with "key=value"
+at the same time.
+
 =item B<key=value>
 
 It is possible to pass I<key=value> pairs on the command line to provide
@@ -197,6 +202,11 @@ B<OPTIONS>
 
 Use the given configuration file.
 
+=item B<-j>
+
+The provided I<configfile> is in JSON format. Cannot be used with "key=value"
+at the same time.
+
 =item B<key=value>
 
 It is possible to pass I<key=value> pairs on the command line to
@@ -423,6 +433,10 @@ Send <config> instead of config file from creation.
 
 Print huge (!) amount of debug during the migration process.
 
+=item B<-j>
+
+The provided I<config> is in JSON format.
+
 =back
 
 =item B<remus> [I<OPTIONS>] I<domain-id> I<host>
@@ -528,6 +542,9 @@ Attach to domain's VNC server, forking a vncviewer process.
 
 Pass VNC password to vncviewer via stdin.
 
+=item B<-j>
+
+The provided I<ConfigFile> is in JSON format.
 
 
 =back
@@ -551,6 +568,10 @@ Leave domain running after creating the snapshot.
 
 Leave domain paused after creating the snapshot.
 
+=item B<-j>
+
+The provided I<ConfigFile> is in JSON format.
+
 =back
 
 =item B<sharing> [I<domain-id>]
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index c6a9a0d..970eba2 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1081,6 +1081,7 @@ void libxl_cpuid_set(libxl_ctx *ctx, uint32_t domid,
  *
  *  userid        Data contents
  *  "xl"          domain config file in xl format, Unix line endings
+ *  "xl-json"     domain config in JSON format generated by xl
  *  "libvirt-xml" domain config file in libvirt XML format.  See
  *                http://libvirt.org/formatdomain.html
  *
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 289ea9a..7443d86 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -110,6 +110,8 @@ static const char migrate_report[]=
    *            from target to source
    */
 
+#define XL_MANDATORY_FLAG_JSON (1U << 0) /* config data is in JSON format  */
+#define XL_MANDATORY_FLAG_ALL  (XL_MANDATORY_FLAG_JSON)
 struct save_file_header {
     char magic[32]; /* savefileheader_magic */
     /* All uint32_ts are in domain's byte order. */
@@ -151,6 +153,7 @@ struct domain_create {
     int console_autoconnect;
     int checkpointed_stream;
     const char *config_file;
+    int config_in_json;
     const char *extra_config; /* extra config string */
     const char *restore_file;
     int migrate_fd; /* -1 means none */
@@ -693,6 +696,73 @@ static void parse_top_level_sdl_options(XLU_Config *config,
     xlu_cfg_replace_string (config, "xauthority", &sdl->xauthority, 0);
 }
 
+static void nic_update_default(libxl_domain_config *d_config)
+{
+    int i;
+    libxl_device_nic *nic;
+
+    for (i = 0; i < d_config->num_nics; i++) {
+        nic = &d_config->nics[i];
+
+        if (default_vifscript) {
+            free(nic->script);
+            nic->script = strdup(default_vifscript);
+        }
+
+        if (default_bridge) {
+            free(nic->bridge);
+            nic->bridge = strdup(default_bridge);
+        }
+
+        if (default_gatewaydev) {
+            free(nic->gatewaydev);
+            nic->gatewaydev = strdup(default_gatewaydev);
+        }
+
+        if (default_vifbackend) {
+            free(nic->backend_domname);
+            nic->backend_domname = strdup(default_vifbackend);
+        }
+    }
+}
+
+static void parse_config_data_json(char *config_data,
+                                   int config_len,
+                                   libxl_domain_config *d_config)
+{
+    int ret;
+
+    if (!config_len) {
+        fprintf(stderr, "Config data stream empty\n");
+        exit(1);
+    }
+
+    /* Make sure this string ends with \0 -- the parser expects a NULL
+     * terminated string.
+     */
+    if (config_data[config_len-1] != '\0') {
+        config_data = realloc(config_data, config_len + 1);
+        if (!config_data) {
+            fprintf(stderr, "Failed to realloc config_data\n");
+            exit(1);
+        }
+        config_data[config_len] = '\0';
+    }
+
+    ret = libxl_domain_config_from_json(ctx, d_config, config_data);
+    if (ret) {
+        fprintf(stderr, "Failed to parse config\n");
+        exit(1);
+    }
+
+    if (blkdev_start) {
+        free(d_config->b_info.blkdev_start);
+        d_config->b_info.blkdev_start = strdup(blkdev_start);
+    }
+
+    nic_update_default(d_config);
+}
+
 static void parse_config_data(const char *config_source,
                               const char *config_data,
                               int config_len,
@@ -930,6 +1000,8 @@ static void parse_config_data(const char *config_source,
         b_info->rtc_timeoffset = l;
 
     if (dom_info && !xlu_cfg_get_long(config, "vncviewer", &l, 0)) {
+        fprintf(stderr, "WARNING: \"vncviewer\" option found. It might be 
removed in future release. "
+            "Use \"-V\" option of \"xl create\" to automatically spawn 
vncviewer.\n");
         /* Command line arguments must take precedence over what's
          * specified in the configuration file. */
         if (!dom_info->vnc)
@@ -1243,26 +1315,6 @@ static void parse_config_data(const char *config_source,
             libxl_device_nic_init(nic);
             nic->devid = d_config->num_nics;
 
-            if (default_vifscript) {
-                free(nic->script);
-                nic->script = strdup(default_vifscript);
-            }
-
-            if (default_bridge) {
-                free(nic->bridge);
-                nic->bridge = strdup(default_bridge);
-            }
-
-            if (default_gatewaydev) {
-                free(nic->gatewaydev);
-                nic->gatewaydev = strdup(default_gatewaydev);
-            }
-
-            if (default_vifbackend) {
-                free(nic->backend_domname);
-                nic->backend_domname = strdup(default_vifbackend);
-            }
-
             p = strtok(buf2, ",");
             if (!p)
                 goto skip_nic;
@@ -1334,6 +1386,8 @@ skip_nic:
         }
     }
 
+    nic_update_default(d_config);
+
     if (!xlu_cfg_get_list(config, "vif2", NULL, 0, 0)) {
         fprintf(stderr, "WARNING: vif2: netchannel2 is deprecated and not 
supported by xl\n");
     }
@@ -1699,12 +1753,13 @@ skip_vfb:
 }
 
 static void reload_domain_config(uint32_t domid,
-                                 uint8_t **config_data, int *config_len)
+                                 uint8_t **config_data, int *config_len,
+                                 bool *config_in_json)
 {
     uint8_t *t_data;
     int ret, t_len;
 
-    ret = libxl_userdata_retrieve(ctx, domid, "xl", &t_data, &t_len);
+    ret = libxl_userdata_retrieve(ctx, domid, "xl-json", &t_data, &t_len);
     if (ret) {
         LOG("failed to retrieve guest configuration (rc=%d). "
             "reusing old configuration", ret);
@@ -1714,6 +1769,7 @@ static void reload_domain_config(uint32_t domid,
     free(*config_data);
     *config_data = t_data;
     *config_len = t_len;
+    *config_in_json = true;
 }
 
 /* Returns 1 if domain should be restarted,
@@ -1722,6 +1778,7 @@ static void reload_domain_config(uint32_t domid,
 static int handle_domain_death(uint32_t *r_domid,
                                libxl_event *event,
                                uint8_t **config_data, int *config_len,
+                               bool *config_in_json,
                                libxl_domain_config *d_config)
 
 {
@@ -1779,12 +1836,14 @@ static int handle_domain_death(uint32_t *r_domid,
         break;
 
     case LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME:
-        reload_domain_config(*r_domid, config_data, config_len);
+        reload_domain_config(*r_domid, config_data, config_len,
+                             config_in_json);
         restart = 2;
         break;
 
     case LIBXL_ACTION_ON_SHUTDOWN_RESTART:
-        reload_domain_config(*r_domid, config_data, config_len);
+        reload_domain_config(*r_domid, config_data, config_len,
+                             config_in_json);
 
         restart = 1;
         /* fall-through */
@@ -1965,11 +2024,43 @@ static void 
evdisable_disk_ejects(libxl_evgen_disk_eject **diskws,
     }
 }
 
+/* Selectively update domain configuration struct. This function is
+ * only used when creating domain.
+ *
+ * src contains a libxl_domain_config that is used by libxl to create
+ * a domain. Presumably libxl fills in relevant information when
+ * creating a domain.
+ *
+ * dst contains a vanilla copy of domain configuration from user
+ * supplied config file. It serves as a template.
+ *
+ * The end result is that dst now contains all relevant information to
+ * reconstruct a domain based on user's configurations and libxl's
+ * decision.
+ */
+static void update_domain_config(libxl_domain_config *dst,
+                                 libxl_domain_config *src)
+{
+    int i;
+
+    /* update network interface information */
+    for (i = 0; i < src->num_nics; i++)
+        libxl_mac_copy(ctx, &dst->nics[i].mac, &src->nics[i].mac);
+
+    /* update vTPM information */
+    for (i = 0; i < src->num_vtpms; i++)
+        libxl_uuid_copy(&dst->vtpms[i].uuid, &src->vtpms[i].uuid);
+
+    /* update guest UUID */
+    libxl_uuid_copy(&dst->c_info.uuid, &src->c_info.uuid);
+}
+
 static uint32_t create_domain(struct domain_create *dom_info)
 {
     uint32_t domid = INVALID_DOMID;
 
-    libxl_domain_config d_config;
+    libxl_domain_config d_config, d_config_saved;
+    char *d_config_json = NULL;
 
     int debug = dom_info->debug;
     int daemonize = dom_info->daemonize;
@@ -1990,6 +2081,7 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
     libxl_evgen_disk_eject **diskws = NULL; /* one per disk */
     void *config_data = 0;
     int config_len = 0;
+    bool config_in_json;
     int restore_fd = -1;
     const libxl_asyncprogress_how *autoconnect_console_how;
     struct save_file_header hdr;
@@ -1997,6 +2089,7 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
     int restoring = (restore_file || (migrate_fd >= 0));
 
     libxl_domain_config_init(&d_config);
+    libxl_domain_config_init(&d_config_saved);
 
     if (restoring) {
         uint8_t *optdata_begin = 0;
@@ -2036,7 +2129,7 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
                 restore_source, hdr.mandatory_flags, hdr.optional_flags,
                 hdr.optional_data_len);
 
-        badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ );
+        badflags = hdr.mandatory_flags & ~XL_MANDATORY_FLAG_ALL;
         if (badflags) {
             fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" "
                     "which are not supported; need newer xl\n",
@@ -2064,7 +2157,9 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
         optdata_here = optdata_begin;
 
         if (OPTDATA_LEFT) {
-            fprintf(stderr, " Savefile contains xl domain config\n");
+            fprintf(stderr, " Savefile contains xl domain config%s\n",
+                    !!(hdr.mandatory_flags & XL_MANDATORY_FLAG_JSON)
+                    ? " in JSON format" : "");
             WITH_OPTDATA(4, {
                 memcpy(u32buf.b, optdata_here, 4);
                 config_len = u32buf.u32;
@@ -2104,6 +2199,7 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
                 extra_config);
         }
         config_source=config_file;
+        config_in_json = !!dom_info->config_in_json;
     } else {
         if (!config_data) {
             fprintf(stderr, "Config file not specified and"
@@ -2111,12 +2207,22 @@ static uint32_t create_domain(struct domain_create 
*dom_info)
             return ERROR_INVAL;
         }
         config_source = "<saved>";
+        config_in_json = !!(hdr.mandatory_flags & XL_MANDATORY_FLAG_JSON);
     }
 
     if (!dom_info->quiet)
         printf("Parsing config from %s\n", config_source);
 
-    parse_config_data(config_source, config_data, config_len, &d_config, 
dom_info);
+    if (config_in_json)
+        parse_config_data_json(config_data, config_len, &d_config);
+    else
+        parse_config_data(config_source, config_data, config_len,
+                          &d_config, dom_info);
+
+    /* Save a copy of vanilla domain configuration, as libxl routines
+     * will fill in more stuffs.
+     */
+    libxl_domain_config_copy(ctx, &d_config_saved, &d_config);
 
     if (migrate_fd >= 0) {
         if (d_config.c_info.name) {
@@ -2211,8 +2317,16 @@ start:
         free(vcpu_to_pcpu); vcpu_to_pcpu = NULL;
     }
 
-    ret = libxl_userdata_store(ctx, domid, "xl",
-                                    config_data, config_len);
+    update_domain_config(&d_config_saved, &d_config);
+    d_config_json = libxl_domain_config_to_json(ctx, &d_config_saved);
+    if (d_config_json == NULL) {
+        perror("cannot generate JSON object of domain configuration");
+        ret = ERROR_FAIL;
+        goto error_out;
+    }
+    ret = libxl_userdata_store(ctx, domid, "xl-json",
+                               (const uint8_t *)d_config_json,
+                               strlen(d_config_json));
     if (ret) {
         perror("cannot save config file");
         ret = ERROR_FAIL;
@@ -2277,7 +2391,7 @@ start:
                 event->u.domain_shutdown.shutdown_reason);
             switch (handle_domain_death(&domid, event,
                                         (uint8_t **)&config_data, &config_len,
-                                        &d_config)) {
+                                        &config_in_json, &d_config)) {
             case 2:
                 if (!preserve_domain(&domid, event, &d_config)) {
                     /* If we fail then exit leaving the old domain in place. */
@@ -2317,8 +2431,11 @@ start:
                 /* Reparse the configuration in case it has changed */
                 libxl_domain_config_dispose(&d_config);
                 libxl_domain_config_init(&d_config);
-                parse_config_data(config_source, config_data, config_len,
-                                  &d_config, dom_info);
+                if (config_in_json)
+                    parse_config_data_json(config_data, config_len, &d_config);
+                else
+                    parse_config_data(config_source, config_data, config_len,
+                                      &d_config, dom_info);
 
                 /*
                  * XXX FIXME: If this sleep is not there then domain
@@ -2371,9 +2488,12 @@ out:
         close(logfile);
 
     libxl_domain_config_dispose(&d_config);
+    libxl_domain_config_dispose(&d_config_saved);
 
     free(config_data);
 
+    free(d_config_json);
+
     console_child_report(child_console);
 
     if (deathw)
@@ -3124,12 +3244,13 @@ static void list_domains_details(const libxl_dominfo 
*info, int nb_domain)
         /* no detailed info available on dom0 */
         if (info[i].domid == 0)
             continue;
-        rc = libxl_userdata_retrieve(ctx, info[i].domid, "xl", &data, &len);
+        rc = libxl_userdata_retrieve(ctx, info[i].domid, "xl-json",
+                                     &data, &len);
         if (rc)
             continue;
         CHK_SYSCALL(asprintf(&config_source, "<domid %d data>", 
info[i].domid));
         libxl_domain_config_init(&d_config);
-        parse_config_data(config_source, (char *)data, len, &d_config, NULL);
+        parse_config_data_json((char *)data, len, &d_config);
         if (default_output_format == OUTPUT_FORMAT_JSON)
             s = printf_info_one_json(hand, info[i].domid, &d_config);
         else
@@ -3318,7 +3439,8 @@ static void core_dump_domain(uint32_t domid, const char 
*filename)
 static void save_domain_core_begin(uint32_t domid,
                                    const char *override_config_file,
                                    uint8_t **config_data_r,
-                                   int *config_len_r)
+                                   int *config_len_r,
+                                   bool *config_in_json)
 {
     int rc;
 
@@ -3329,9 +3451,12 @@ static void save_domain_core_begin(uint32_t domid,
         rc = libxl_read_file_contents(ctx, override_config_file,
                                       &config_v, config_len_r);
         *config_data_r = config_v;
+        /* leave config_in_json untouched */
     } else {
-        rc = libxl_userdata_retrieve(ctx, domid, "xl",
+        rc = libxl_userdata_retrieve(ctx, domid, "xl-json",
                                      config_data_r, config_len_r);
+        if (!rc)
+            *config_in_json = true;
     }
     if (rc) {
         fputs("Unable to get config file\n",stderr);
@@ -3340,7 +3465,8 @@ static void save_domain_core_begin(uint32_t domid,
 }
 
 static void save_domain_core_writeconfig(int fd, const char *source,
-                                  const uint8_t *config_data, int config_len)
+                                         const uint8_t *config_data, int 
config_len,
+                                         bool config_in_json)
 {
     struct save_file_header hdr;
     uint8_t *optdata_begin;
@@ -3364,6 +3490,8 @@ static void save_domain_core_writeconfig(int fd, const 
char *source,
     u32buf.u32 = config_len;
     ADD_OPTDATA(u32buf.b,    4);
     ADD_OPTDATA(config_data, config_len);
+    if (config_in_json)
+        hdr.mandatory_flags |= XL_MANDATORY_FLAG_JSON;
 
     /* that's the optional data */
 
@@ -3382,17 +3510,19 @@ static void save_domain_core_writeconfig(int fd, const 
char *source,
 }
 
 static int save_domain(uint32_t domid, const char *filename, int checkpoint,
-                            int leavepaused, const char *override_config_file)
+                       int leavepaused, const char *override_config_file,
+                       bool config_in_json)
 {
     int fd;
     uint8_t *config_data;
     int config_len;
 
     save_domain_core_begin(domid, override_config_file,
-                           &config_data, &config_len);
+                           &config_data, &config_len, &config_in_json);
 
     if (!config_len) {
         fputs(" Savefile will not contain xl domain config\n", stderr);
+        config_in_json = false;
     }
 
     fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
@@ -3401,7 +3531,8 @@ static int save_domain(uint32_t domid, const char 
*filename, int checkpoint,
         exit(2);
     }
 
-    save_domain_core_writeconfig(fd, filename, config_data, config_len);
+    save_domain_core_writeconfig(fd, filename, config_data, config_len,
+                                 config_in_json);
 
     int rc = libxl_domain_suspend(ctx, domid, fd, 0, NULL);
     close(fd);
@@ -3542,7 +3673,7 @@ static void migration_child_report(int recv_fd) {
 
 static void migrate_do_preamble(int send_fd, int recv_fd, pid_t child,
                                 uint8_t *config_data, int config_len,
-                                const char *rune)
+                                bool config_in_json, const char *rune)
 {
     int rc = 0;
 
@@ -3561,12 +3692,13 @@ static void migrate_do_preamble(int send_fd, int 
recv_fd, pid_t child,
     }
 
     save_domain_core_writeconfig(send_fd, "migration stream",
-                                 config_data, config_len);
+                                 config_data, config_len, config_in_json);
 
 }
 
 static void migrate_domain(uint32_t domid, const char *rune, int debug,
-                           const char *override_config_file)
+                           const char *override_config_file,
+                           bool config_in_json)
 {
     pid_t child = -1;
     int rc;
@@ -3577,7 +3709,7 @@ static void migrate_domain(uint32_t domid, const char 
*rune, int debug,
     int config_len, flags = LIBXL_SUSPEND_LIVE;
 
     save_domain_core_begin(domid, override_config_file,
-                           &config_data, &config_len);
+                           &config_data, &config_len, &config_in_json);
 
     if (!config_len) {
         fprintf(stderr, "No config file stored for running domain and "
@@ -3588,7 +3720,7 @@ static void migrate_domain(uint32_t domid, const char 
*rune, int debug,
     child = create_migration_child(rune, &send_fd, &recv_fd);
 
     migrate_do_preamble(send_fd, recv_fd, child, config_data, config_len,
-                        rune);
+                        config_in_json, rune);
 
     xtl_stdiostream_adjust_flags(logger, XTL_STDIOSTREAM_HIDE_PROGRESS, 0);
 
@@ -3848,7 +3980,8 @@ int main_restore(int argc, char **argv)
     const char *config_file = NULL;
     struct domain_create dom_info;
     int paused = 0, debug = 0, daemonize = 1, monitor = 1,
-        console_autoconnect = 0, vnc = 0, vncautopass = 0;
+        console_autoconnect = 0, vnc = 0, vncautopass = 0,
+        config_in_json = 0;
     int opt, rc;
     static struct option opts[] = {
         {"vncviewer", 0, 0, 'V'},
@@ -3857,7 +3990,7 @@ int main_restore(int argc, char **argv)
         {0, 0, 0, 0}
     };
 
-    SWITCH_FOREACH_OPT(opt, "FhcpdeVA", opts, "restore", 1) {
+    SWITCH_FOREACH_OPT(opt, "FhcpdeVAj", opts, "restore", 1) {
     case 'c':
         console_autoconnect = 1;
         break;
@@ -3880,6 +4013,9 @@ int main_restore(int argc, char **argv)
     case 'A':
         vnc = vncautopass = 1;
         break;
+    case 'j':
+        config_in_json = 1;
+        break;
     }
 
     if (argc-optind == 1) {
@@ -3892,12 +4028,19 @@ int main_restore(int argc, char **argv)
         return 2;
     }
 
+    if (!config_file && config_in_json) {
+        fprintf(stderr, "\"-j\" specified but no config file provided\n");
+        help("restore");
+        return 2;
+    }
+
     memset(&dom_info, 0, sizeof(dom_info));
     dom_info.debug = debug;
     dom_info.daemonize = daemonize;
     dom_info.monitor = monitor;
     dom_info.paused = paused;
     dom_info.config_file = config_file;
+    dom_info.config_in_json = config_in_json;
     dom_info.restore_file = checkpoint_file;
     dom_info.migrate_fd = -1;
     dom_info.vnc = vnc;
@@ -3948,17 +4091,21 @@ int main_save(int argc, char **argv)
     uint32_t domid;
     const char *filename;
     const char *config_filename = NULL;
+    bool config_in_json = false;
     int checkpoint = 0;
     int leavepaused = 0;
     int opt;
 
-    SWITCH_FOREACH_OPT(opt, "cp", NULL, "save", 2) {
+    SWITCH_FOREACH_OPT(opt, "cpj", NULL, "save", 2) {
     case 'c':
         checkpoint = 1;
         break;
     case 'p':
         leavepaused = 1;
         break;
+    case 'j':
+        config_in_json = true;
+        break;
     }
 
     if (argc-optind > 3) {
@@ -3966,12 +4113,19 @@ int main_save(int argc, char **argv)
         return 2;
     }
 
+    if (!config_filename && config_in_json) {
+        fprintf(stderr, "\"-j\" specified but no config file provided\n");
+        help("save");
+        return 2;
+    }
+
     domid = find_domain(argv[optind]);
     filename = argv[optind + 1];
     if ( argc - optind >= 3 )
         config_filename = argv[optind + 2];
 
-    save_domain(domid, filename, checkpoint, leavepaused, config_filename);
+    save_domain(domid, filename, checkpoint, leavepaused, config_filename,
+                config_in_json);
     return 0;
 }
 
@@ -3979,6 +4133,7 @@ int main_migrate(int argc, char **argv)
 {
     uint32_t domid;
     const char *config_filename = NULL;
+    bool config_in_json = false;
     const char *ssh_command = "ssh";
     char *rune = NULL;
     char *host;
@@ -3989,7 +4144,7 @@ int main_migrate(int argc, char **argv)
         {0, 0, 0, 0}
     };
 
-    SWITCH_FOREACH_OPT(opt, "FC:s:e", opts, "migrate", 2) {
+    SWITCH_FOREACH_OPT(opt, "FC:s:ej", opts, "migrate", 2) {
     case 'C':
         config_filename = optarg;
         break;
@@ -4003,11 +4158,20 @@ int main_migrate(int argc, char **argv)
         daemonize = 0;
         monitor = 0;
         break;
+    case 'j':
+        config_in_json = true;
+        break;
     case 0x100:
         debug = 1;
         break;
     }
 
+    if (!config_filename && config_in_json) {
+        fprintf(stderr, "\"-j\" specified but no config file provided\n");
+        help("migrate");
+        return 2;
+    }
+
     domid = find_domain(argv[optind]);
     host = argv[optind + 1];
 
@@ -4036,7 +4200,7 @@ int main_migrate(int argc, char **argv)
             return 1;
     }
 
-    migrate_domain(domid, rune, debug, config_filename);
+    migrate_domain(domid, rune, debug, config_filename, config_in_json);
     return 0;
 }
 #endif
@@ -4265,7 +4429,8 @@ int main_create(int argc, char **argv)
     char extra_config[1024];
     struct domain_create dom_info;
     int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0,
-        quiet = 0, monitor = 1, vnc = 0, vncautopass = 0;
+        quiet = 0, monitor = 1, vnc = 0, vncautopass = 0,
+        config_in_json = 0;
     int opt, rc;
     static struct option opts[] = {
         {"dryrun", 0, 0, 'n'},
@@ -4282,7 +4447,7 @@ int main_create(int argc, char **argv)
         argc--; argv++;
     }
 
-    SWITCH_FOREACH_OPT(opt, "Fhnqf:pcdeVA", opts, "create", 0) {
+    SWITCH_FOREACH_OPT(opt, "Fhnqf:pcdeVAj", opts, "create", 0) {
     case 'f':
         filename = optarg;
         break;
@@ -4314,6 +4479,9 @@ int main_create(int argc, char **argv)
     case 'A':
         vnc = vncautopass = 1;
         break;
+    case 'j':
+        config_in_json = 1;
+        break;
     }
 
     extra_config[0] = '\0';
@@ -4329,6 +4497,11 @@ int main_create(int argc, char **argv)
         }
     }
 
+    if (config_in_json && strlen(extra_config)) {
+        fprintf(stderr, "\"-j\" specified, key=value extra configs ignored\n");
+        extra_config[0] = '\0';
+    }
+
     memset(&dom_info, 0, sizeof(dom_info));
     dom_info.debug = debug;
     dom_info.daemonize = daemonize;
@@ -4337,6 +4510,7 @@ int main_create(int argc, char **argv)
     dom_info.dryrun = dryrun_only;
     dom_info.quiet = quiet;
     dom_info.config_file = filename;
+    dom_info.config_in_json = config_in_json;
     dom_info.extra_config = extra_config;
     dom_info.migrate_fd = -1;
     dom_info.vnc = vnc;
@@ -4358,6 +4532,7 @@ int main_config_update(int argc, char **argv)
     char extra_config[1024];
     void *config_data = 0;
     int config_len = 0;
+    bool config_in_json = false;
     libxl_domain_config d_config;
     int opt, rc;
     int debug = 0;
@@ -4381,13 +4556,15 @@ int main_config_update(int argc, char **argv)
         argc--; argv++;
     }
 
-    SWITCH_FOREACH_OPT(opt, "dhqf:", opts, "config_update", 0) {
+    SWITCH_FOREACH_OPT(opt, "dhqf:j", opts, "config_update", 0) {
     case 'd':
         debug = 1;
         break;
     case 'f':
         filename = optarg;
         break;
+    case 'j':
+        config_in_json = true;
     }
 
     extra_config[0] = '\0';
@@ -4402,6 +4579,12 @@ int main_config_update(int argc, char **argv)
             return 2;
         }
     }
+
+    if (config_in_json && strlen(extra_config)) {
+        fprintf(stderr, "\"-j\" specified, key=value extra configs ignored\n");
+        extra_config[0] = '\0';
+    }
+
     if (filename) {
         free(config_data);  config_data = 0;
         rc = libxl_read_file_contents(ctx, filename,
@@ -4430,19 +4613,26 @@ int main_config_update(int argc, char **argv)
 
     libxl_domain_config_init(&d_config);
 
-    parse_config_data(filename, config_data, config_len, &d_config, NULL);
+    if (config_in_json)
+        parse_config_data_json(config_data, config_len, &d_config);
+    else
+        parse_config_data(filename, config_data, config_len, &d_config, NULL);
 
     if (debug || dryrun_only)
         printf_info(default_output_format, -1, &d_config);
 
     if (!dryrun_only) {
+        char *d_config_json = NULL;
         fprintf(stderr, "setting dom%d configuration\n", domid);
-        rc = libxl_userdata_store(ctx, domid, "xl",
-                                   config_data, config_len);
+        d_config_json = libxl_domain_config_to_json(ctx, &d_config);
+        rc = libxl_userdata_store(ctx, domid, "xl-json",
+                                  (const uint8_t*)d_config_json,
+                                  strlen(d_config_json));
         if (rc) {
             fprintf(stderr, "failed to update configuration\n");
             exit(1);
         }
+        free(d_config_json);
     }
 
     libxl_domain_config_dispose(&d_config);
@@ -7196,6 +7386,7 @@ int main_remus(int argc, char **argv)
     pid_t child = -1;
     uint8_t *config_data;
     int config_len;
+    bool config_in_json;
 
     memset(&r_info, 0, sizeof(libxl_domain_remus_info));
     /* Defaults */
@@ -7241,7 +7432,8 @@ int main_remus(int argc, char **argv)
                 return 1;
         }
 
-        save_domain_core_begin(domid, NULL, &config_data, &config_len);
+        save_domain_core_begin(domid, NULL, &config_data, &config_len,
+                               &config_in_json);
 
         if (!config_len) {
             fprintf(stderr, "No config file stored for running domain and "
@@ -7251,7 +7443,8 @@ int main_remus(int argc, char **argv)
 
         child = create_migration_child(rune, &send_fd, &recv_fd);
 
-        migrate_do_preamble(send_fd, recv_fd, child, config_data, config_len,
+        migrate_do_preamble(send_fd, recv_fd, child,
+                            config_data, config_len, true /* config_in_json */,
                             rune);
 
         if (ssh_command[0])
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index 4279b9f..cdc8e14 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -33,7 +33,8 @@ struct cmd_spec cmd_table[] = {
       "-e                      Do not wait in the background for the death of 
the domain.\n"
       "-V, --vncviewer         Connect to the VNC display after the domain is 
created.\n"
       "-A, --vncviewer-autopass\n"
-      "                        Pass VNC password to viewer via stdin."
+      "                        Pass VNC password to viewer via stdin.\n"
+      "-j                      Config file in \"xl-json\" format."
     },
     { "config-update",
       &main_config_update, 1, 1,
@@ -43,6 +44,7 @@ struct cmd_spec cmd_table[] = {
       "-h                      Print this help.\n"
       "-f FILE, --defconfig=FILE\n                     Use the given 
configuration file.\n"
       "-d                      Enable debug messages.\n"
+      "-j                      <ConfigFile> in \"xl-json\" format."
     },
     { "list",
       &main_list, 0, 0,
@@ -147,7 +149,8 @@ struct cmd_spec cmd_table[] = {
       "[options] <Domain> <CheckpointFile> [<ConfigFile>]",
       "-h  Print this help.\n"
       "-c  Leave domain running after creating the snapshot.\n"
-      "-p  Leave domain paused after creating the snapshot."
+      "-p  Leave domain paused after creating the snapshot.\n"
+      "-j  Config file is in \"xl-json\" format (ConfigFile cannot be null)."
     },
     { "migrate",
       &main_migrate, 0, 1,
@@ -155,6 +158,7 @@ struct cmd_spec cmd_table[] = {
       "[options] <Domain> <host>",
       "-h              Print this help.\n"
       "-C <config>     Send <config> instead of config file from creation.\n"
+      "-j              <config> is in \"xl-json\" format.\n"
       "-s <sshcommand> Use <sshcommand> instead of ssh.  String will be 
passed\n"
       "                to sh. If empty, run <host> instead of ssh <host> xl\n"
       "                migrate-receive [-d -e]\n"
@@ -171,7 +175,8 @@ struct cmd_spec cmd_table[] = {
       "-e                       Do not wait in the background for the death of 
the domain.\n"
       "-d                       Enable debug messages.\n"
       "-V, --vncviewer          Connect to the VNC display after the domain is 
created.\n"
-      "-A, --vncviewer-autopass Pass VNC password to viewer via stdin."
+      "-A, --vncviewer-autopass Pass VNC password to viewer via stdin.\n"
+      "-j                       Config file is in \"xl-json\" format 
(ConfigFile cannot be null)."
     },
     { "migrate-receive",
       &main_migrate_receive, 0, 1,
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.