Blame SOURCES/0113-p2v-Use-a-wrapper-script-instead-of-long-virt-v2v-co.patch

e76f14
From 11ef6d48abcfc90c0a6e795a067547c289e883d6 Mon Sep 17 00:00:00 2001
e76f14
From: "Richard W.M. Jones" <rjones@redhat.com>
e76f14
Date: Sat, 18 Jun 2016 14:44:24 +0100
e76f14
Subject: [PATCH] p2v: Use a wrapper script instead of long virt-v2v command
e76f14
 lne.
e76f14
e76f14
Instead of constructing and directly executing a long virt-v2v command
e76f14
line, build a wrapper script with the same command line and send it to
e76f14
the remote server (stored in /<remote_dir>/virt-v2v-wrapper.sh).
e76f14
e76f14
This will make it a bit easier to construct more complex virt-v2v
e76f14
wrappers.
e76f14
e76f14
Note this commit on its own is a simple refactoring and does not
e76f14
change any functionality.
e76f14
e76f14
(cherry picked from commit 514893b68b6180b3adc5bb762e9d67054a9a7f63)
e76f14
---
e76f14
 p2v/conversion.c | 203 +++++++++++++++++++++++++++++++++----------------------
e76f14
 p2v/p2v.h        |   2 +-
e76f14
 p2v/ssh.c        |  25 ++++++-
e76f14
 p2v/virt-p2v.pod |  17 +++--
e76f14
 4 files changed, 159 insertions(+), 88 deletions(-)
e76f14
e76f14
diff --git a/p2v/conversion.c b/p2v/conversion.c
e76f14
index 5265a76..decaf7c 100644
e76f14
--- a/p2v/conversion.c
e76f14
+++ b/p2v/conversion.c
e76f14
@@ -27,6 +27,7 @@
e76f14
 #include <unistd.h>
e76f14
 #include <time.h>
e76f14
 #include <errno.h>
e76f14
+#include <error.h>
e76f14
 #include <locale.h>
e76f14
 #include <libintl.h>
e76f14
 #include <netdb.h>
e76f14
@@ -78,11 +79,11 @@ struct data_conn {
e76f14
   int nbd_remote_port;      /* remote NBD port on conversion server */
e76f14
 };
e76f14
 
e76f14
-static int send_quoted (mexp_h *, const char *s);
e76f14
 static pid_t start_qemu_nbd (int nbd_local_port, const char *device);
e76f14
 static int wait_qemu_nbd (int nbd_local_port, int timeout_seconds);
e76f14
 static void cleanup_data_conns (struct data_conn *data_conns, size_t nr);
e76f14
 static char *generate_libvirt_xml (struct config *, struct data_conn *);
e76f14
+static char *generate_wrapper_script (struct config *, const char *remote_dir);
e76f14
 static const char *map_interface_to_network (struct config *, const char *interface);
e76f14
 
e76f14
 static char *conversion_error;
e76f14
@@ -168,7 +169,8 @@ start_conversion (struct config *config,
e76f14
   size_t i, len;
e76f14
   const size_t nr_disks = guestfs_int_count_strings (config->disks);
e76f14
   struct data_conn data_conns[nr_disks];
e76f14
-  CLEANUP_FREE char *remote_dir = NULL, *libvirt_xml = NULL;
e76f14
+  CLEANUP_FREE char *remote_dir = NULL, *libvirt_xml = NULL,
e76f14
+    *wrapper_script = NULL;
e76f14
   time_t now;
e76f14
   struct tm tm;
e76f14
   mexp_h *control_h = NULL;
e76f14
@@ -276,7 +278,18 @@ start_conversion (struct config *config,
e76f14
     goto out;
e76f14
 
e76f14
 #if DEBUG_STDERR
e76f14
-  fprintf (stderr, "%s: libvirt XML:\n%s", guestfs_int_program_name, libvirt_xml);
e76f14
+  fprintf (stderr, "%s: libvirt XML:\n%s",
e76f14
+           guestfs_int_program_name, libvirt_xml);
e76f14
+#endif
e76f14
+
e76f14
+  /* Generate the virt-v2v wrapper script. */
e76f14
+  wrapper_script = generate_wrapper_script (config, remote_dir);
e76f14
+  if (wrapper_script == NULL)
e76f14
+    goto out;
e76f14
+
e76f14
+#if DEBUG_STDERR
e76f14
+  fprintf (stderr, "%s: wrapper script:\n%s",
e76f14
+           guestfs_int_program_name, wrapper_script);
e76f14
 #endif
e76f14
 
e76f14
   /* Get the output from the 'dmesg' command.  We will store this
e76f14
@@ -305,7 +318,9 @@ start_conversion (struct config *config,
e76f14
   if (notify_ui)
e76f14
     notify_ui (NOTIFY_STATUS, _("Setting up the control connection ..."));
e76f14
 
e76f14
-  control_h = start_remote_connection (config, remote_dir, libvirt_xml, dmesg);
e76f14
+  control_h = start_remote_connection (config,
e76f14
+                                       remote_dir, libvirt_xml,
e76f14
+                                       wrapper_script, dmesg);
e76f14
   if (control_h == NULL) {
e76f14
     const char *err = get_ssh_error ();
e76f14
 
e76f14
@@ -317,66 +332,18 @@ start_conversion (struct config *config,
e76f14
   if (notify_ui)
e76f14
     notify_ui (NOTIFY_STATUS, _("Doing conversion ..."));
e76f14
 
e76f14
-  /* Build the virt-v2v command up in pieces to make the quoting
e76f14
-   * slightly more sane.
e76f14
-   */
e76f14
-  if (mexp_printf (control_h, "( %s virt-v2v%s%s -i libvirtxml",
e76f14
-                   config->sudo ? "sudo -n " : "",
e76f14
-                   config->verbose ? " -v -x" : "",
e76f14
-                   feature_colours_option ? " --colours" : "") == -1) {
e76f14
-  printf_fail:
e76f14
-    set_conversion_error ("mexp_printf: virt-v2v command: %m");
e76f14
+  if (mexp_printf (control_h,
e76f14
+                   /* To simplify things in the wrapper script, it
e76f14
+                    * writes virt-v2v's exit status to
e76f14
+                    * /remote_dir/status, and here we read that and
e76f14
+                    * exit the ssh shell with the same status.
e76f14
+                    */
e76f14
+                   "%s/virt-v2v-wrapper.sh; "
e76f14
+                   "exit $(< %s/status)\n",
e76f14
+                   remote_dir, remote_dir) == -1) {
e76f14
+    set_conversion_error ("mexp_printf: virt-v2v: %m");
e76f14
     goto out;
e76f14
   }
e76f14
-  if (config->output) {         /* -o */
e76f14
-    if (mexp_printf (control_h, " -o ") == -1)
e76f14
-      goto printf_fail;
e76f14
-    if (send_quoted (control_h, config->output) == -1)
e76f14
-      goto printf_fail;
e76f14
-  }
e76f14
-  switch (config->output_allocation) { /* -oa */
e76f14
-  case OUTPUT_ALLOCATION_NONE:
e76f14
-    /* nothing */
e76f14
-    break;
e76f14
-  case OUTPUT_ALLOCATION_SPARSE:
e76f14
-    if (mexp_printf (control_h, " -oa sparse") == -1)
e76f14
-      goto printf_fail;
e76f14
-    break;
e76f14
-  case OUTPUT_ALLOCATION_PREALLOCATED:
e76f14
-    if (mexp_printf (control_h, " -oa preallocated") == -1)
e76f14
-      goto printf_fail;
e76f14
-    break;
e76f14
-  default:
e76f14
-    abort ();
e76f14
-  }
e76f14
-  if (config->output_format) {  /* -of */
e76f14
-    if (mexp_printf (control_h, " -of ") == -1)
e76f14
-      goto printf_fail;
e76f14
-    if (send_quoted (control_h, config->output_format) == -1)
e76f14
-      goto printf_fail;
e76f14
-  }
e76f14
-  if (config->output_storage) { /* -os */
e76f14
-    if (mexp_printf (control_h, " -os ") == -1)
e76f14
-      goto printf_fail;
e76f14
-    if (send_quoted (control_h, config->output_storage) == -1)
e76f14
-      goto printf_fail;
e76f14
-  }
e76f14
-  if (mexp_printf (control_h, " --root first") == -1)
e76f14
-    goto printf_fail;
e76f14
-  if (mexp_printf (control_h, " %s/physical.xml", remote_dir) == -1)
e76f14
-    goto printf_fail;
e76f14
-  /* no stdin, and send stdout and stderr to the same place */
e76f14
-  if (mexp_printf (control_h, " </dev/null 2>&1") == -1)
e76f14
-    goto printf_fail;
e76f14
-  if (mexp_printf (control_h, " ; echo $? > %s/status", remote_dir) == -1)
e76f14
-    goto printf_fail;
e76f14
-  if (mexp_printf (control_h, " ) | tee %s/virt-v2v-conversion-log.txt",
e76f14
-                   remote_dir) == -1)
e76f14
-    goto printf_fail;
e76f14
-  if (mexp_printf (control_h, "; exit $(< %s/status)", remote_dir) == -1)
e76f14
-    goto printf_fail;
e76f14
-  if (mexp_printf (control_h, "\n") == -1)
e76f14
-    goto printf_fail;
e76f14
 
e76f14
   /* Read output from the virt-v2v process and echo it through the
e76f14
    * notify function, until virt-v2v closes the connection.
e76f14
@@ -443,26 +410,6 @@ cancel_conversion (void)
e76f14
   set_cancel_requested (1);
e76f14
 }
e76f14
 
e76f14
-/* Send a shell-quoted string to remote. */
e76f14
-static int
e76f14
-send_quoted (mexp_h *h, const char *s)
e76f14
-{
e76f14
-  if (mexp_printf (h, "\"") == -1)
e76f14
-    return -1;
e76f14
-  while (*s) {
e76f14
-    if (*s == '$' || *s == '`' || *s == '\\' || *s == '"') {
e76f14
-      if (mexp_printf (h, "\\") == -1)
e76f14
-        return -1;
e76f14
-    }
e76f14
-    if (mexp_printf (h, "%c", *s) == -1)
e76f14
-      return -1;
e76f14
-    ++s;
e76f14
-  }
e76f14
-  if (mexp_printf (h, "\"") == -1)
e76f14
-    return -1;
e76f14
-  return 0;
e76f14
-}
e76f14
-
e76f14
 /* Note: returns process ID (> 0) or 0 if there is an error. */
e76f14
 static pid_t
e76f14
 start_qemu_nbd (int port, const char *device)
e76f14
@@ -980,3 +927,95 @@ map_interface_to_network (struct config *config, const char *interface)
e76f14
   /* No mapping found. */
e76f14
   return "default";
e76f14
 }
e76f14
+
e76f14
+/**
e76f14
+ * Print a shell-quoted string on C<fp>.
e76f14
+ */
e76f14
+static void
e76f14
+print_quoted (FILE *fp, const char *s)
e76f14
+{
e76f14
+  fprintf (fp, "\"");
e76f14
+  while (*s) {
e76f14
+    if (*s == '$' || *s == '`' || *s == '\\' || *s == '"')
e76f14
+      fprintf (fp, "\\");
e76f14
+    fprintf (fp, "%c", *s);
e76f14
+    ++s;
e76f14
+  }
e76f14
+  fprintf (fp, "\"");
e76f14
+}
e76f14
+
e76f14
+/**
e76f14
+ * Construct the virt-v2v wrapper script.
e76f14
+ *
e76f14
+ * This will be sent to the remote server, and is easier than trying
e76f14
+ * to "type" a long and complex single command line into the ssh
e76f14
+ * connection when we start the conversion.
e76f14
+ */
e76f14
+static char *
e76f14
+generate_wrapper_script (struct config *config, const char *remote_dir)
e76f14
+{
e76f14
+  FILE *fp;
e76f14
+  char *output = NULL;
e76f14
+  size_t output_len = 0;
e76f14
+
e76f14
+  fp = open_memstream (&output, &output_len);
e76f14
+  if (fp == NULL)
e76f14
+    error (EXIT_FAILURE, errno, "open_memstream");
e76f14
+
e76f14
+  fprintf (fp, "#!/bin/sh -\n");
e76f14
+  fprintf (fp, "\n");
e76f14
+
e76f14
+  /* The virt-v2v command. */
e76f14
+  fprintf (fp, "(\n");
e76f14
+  if (config->sudo)
e76f14
+    fprintf (fp, "sudo -n ");
e76f14
+  fprintf (fp, "virt-v2v");
e76f14
+  if (config->verbose)
e76f14
+    fprintf (fp, " -v -x");
e76f14
+  if (feature_colours_option)
e76f14
+    fprintf (fp, " --colours");
e76f14
+  fprintf (fp, " -i libvirtxml");
e76f14
+
e76f14
+  if (config->output) {         /* -o */
e76f14
+    fprintf (fp, " -o ");
e76f14
+    print_quoted (fp, config->output);
e76f14
+  }
e76f14
+
e76f14
+  switch (config->output_allocation) { /* -oa */
e76f14
+  case OUTPUT_ALLOCATION_NONE:
e76f14
+    /* nothing */
e76f14
+    break;
e76f14
+  case OUTPUT_ALLOCATION_SPARSE:
e76f14
+    fprintf (fp, " -oa sparse");
e76f14
+    break;
e76f14
+  case OUTPUT_ALLOCATION_PREALLOCATED:
e76f14
+    fprintf (fp, " -oa preallocated");
e76f14
+    break;
e76f14
+  default:
e76f14
+    abort ();
e76f14
+  }
e76f14
+
e76f14
+  if (config->output_format) {  /* -of */
e76f14
+    fprintf (fp, " -of ");
e76f14
+    print_quoted (fp, config->output_format);
e76f14
+  }
e76f14
+
e76f14
+  if (config->output_storage) { /* -os */
e76f14
+    fprintf (fp, " -os ");
e76f14
+    print_quoted (fp, config->output_storage);
e76f14
+  }
e76f14
+
e76f14
+  fprintf (fp, " --root first");
e76f14
+  fprintf (fp, " %s/physical.xml", remote_dir);
e76f14
+  /* no stdin, and send stdout and stderr to the same place */
e76f14
+  fprintf (fp, " </dev/null 2>&1");
e76f14
+  fprintf (fp, "\n");
e76f14
+  fprintf (fp, "echo $? > %s/status", remote_dir);
e76f14
+  fprintf (fp, "\n");
e76f14
+  fprintf (fp, " ) | tee %s/virt-v2v-conversion-log.txt", remote_dir);
e76f14
+  fprintf (fp, "\n");
e76f14
+
e76f14
+  fclose (fp);
e76f14
+
e76f14
+  return output;                /* caller frees */
e76f14
+}
e76f14
diff --git a/p2v/p2v.h b/p2v/p2v.h
e76f14
index 12dd210..49c97b6 100644
e76f14
--- a/p2v/p2v.h
e76f14
+++ b/p2v/p2v.h
e76f14
@@ -127,7 +127,7 @@ extern int conversion_is_running (void);
e76f14
 /* ssh.c */
e76f14
 extern int test_connection (struct config *);
e76f14
 extern mexp_h *open_data_connection (struct config *, int *local_port, int *remote_port);
e76f14
-extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, const char *libvirt_xml, const char *dmesg);
e76f14
+extern mexp_h *start_remote_connection (struct config *, const char *remote_dir, const char *libvirt_xml, const char *wrapper_script, const char *dmesg);
e76f14
 extern const char *get_ssh_error (void);
e76f14
 
e76f14
 /* utils.c */
e76f14
diff --git a/p2v/ssh.c b/p2v/ssh.c
e76f14
index 266c236..a8c762d 100644
e76f14
--- a/p2v/ssh.c
e76f14
+++ b/p2v/ssh.c
e76f14
@@ -904,7 +904,7 @@ wait_for_prompt (mexp_h *h)
e76f14
 mexp_h *
e76f14
 start_remote_connection (struct config *config,
e76f14
                          const char *remote_dir, const char *libvirt_xml,
e76f14
-                         const char *dmesg)
e76f14
+                         const char *wrapper_script, const char *dmesg)
e76f14
 {
e76f14
   mexp_h *h;
e76f14
   char magic[9];
e76f14
@@ -960,6 +960,29 @@ start_remote_connection (struct config *config,
e76f14
   if (wait_for_prompt (h) == -1)
e76f14
     goto error;
e76f14
 
e76f14
+  /* Upload the wrapper script to the remote directory. */
e76f14
+  if (mexp_printf (h,
e76f14
+                   "cat > '%s/virt-v2v-wrapper.sh' << '__%s__'\n"
e76f14
+                   "%s"
e76f14
+                   "__%s__\n",
e76f14
+                   remote_dir, magic,
e76f14
+                   wrapper_script,
e76f14
+                   magic) == -1) {
e76f14
+    set_ssh_error ("mexp_printf: %m");
e76f14
+    goto error;
e76f14
+  }
e76f14
+
e76f14
+  if (wait_for_prompt (h) == -1)
e76f14
+    goto error;
e76f14
+
e76f14
+  if (mexp_printf (h, "chmod +x %s/virt-v2v-wrapper.sh\n", remote_dir) == -1) {
e76f14
+    set_ssh_error ("mexp_printf: %m");
e76f14
+    goto error;
e76f14
+  }
e76f14
+
e76f14
+  if (wait_for_prompt (h) == -1)
e76f14
+    goto error;
e76f14
+
e76f14
   if (dmesg != NULL) {
e76f14
     /* Upload the physical host dmesg to the remote directory. */
e76f14
     if (mexp_printf (h,
e76f14
diff --git a/p2v/virt-p2v.pod b/p2v/virt-p2v.pod
e76f14
index 5ceafa7..0c233c5 100644
e76f14
--- a/p2v/virt-p2v.pod
e76f14
+++ b/p2v/virt-p2v.pod
e76f14
@@ -693,6 +693,13 @@ on the conversion server.  If conversion fails, you should examine
e76f14
 this log file, and you may be asked to supply the B<complete>,
e76f14
 B<unedited> log file in any bug reports or support tickets.
e76f14
 
e76f14
+=item F<virt-v2v-wrapper.sh>
e76f14
+
e76f14
+I<(during/after conversion)>
e76f14
+
e76f14
+This is the wrapper script which is used when running virt-v2v.  For
e76f14
+interest only, do not attempt to run this script yourself.
e76f14
+
e76f14
 =back
e76f14
 
e76f14
 Before conversion actually begins, virt-p2v then makes one or more
e76f14
@@ -729,10 +736,12 @@ used.  Secondly libguestfs creates an overlay on top of the NBD
e76f14
 connection which stores writes in a temporary file on the conversion
e76f14
 file.
e76f14
 
e76f14
-The final step is to send the S<C<virt-v2v -i libvirtxml physical.xml ...>>
e76f14
-command to the conversion server over the control connection.  This
e76f14
-references the F<physical.xml> file (see above), which in turn
e76f14
-references the NBD listening port(s) of the data connection(s).
e76f14
+The long S<C<virt-v2v -i libvirtxml physical.xml ...>> command is
e76f14
+wrapped inside a wrapper script and uploaded to the conversion server.
e76f14
+The final step is to run this wrapper script, in turn running the
e76f14
+virt-v2v command.  The virt-v2v command references the F<physical.xml>
e76f14
+file (see above), which in turn references the NBD listening port(s)
e76f14
+of the data connection(s).
e76f14
 
e76f14
 Output from the virt-v2v command (messages, debugging etc) is saved
e76f14
 both in the log file on the conversion server, and sent over the
e76f14
-- 
aa0300
2.7.4
e76f14