Parse <vm> structures.
authorRichard Jones <rjones@redhat.com>
Sat, 29 Nov 2008 14:50:48 +0000 (14:50 +0000)
committerRichard Jones <rjones@redhat.com>
Sat, 29 Nov 2008 14:50:48 +0000 (14:50 +0000)
internal.h
main.c
wui_thread.c

index 77b3907..8f5ec01 100644 (file)
@@ -103,13 +103,18 @@ struct vm {
   char *description;
   int hostid;
   int id;
+  int vnc_port;
+
+  /* Only description, hostid, id and vnc_port fields are required.
+   * The remainder may be NULL / -1 to indicate they were missing in
+   * the data we got back from the WUI.
+   */
   long mem_allocated;          /* Kbytes */
   long mem_used;               /* Kbytes */
   int vcpus_allocated;
   int vcpus_used;
   char *state;
   char *uuid;                  /* Printable UUID. */
-  int vnc_port;
   char *mac_addr;              /* Printable MAC addr. */
 };
 
@@ -169,4 +174,7 @@ extern gboolean main_login_error (gpointer str);
 /* The WUI thread reports a general status error. */
 extern gboolean main_status_error (gpointer str);
 
+/* The WUI thread has updated the vm list. */
+extern gboolean main_vmlist_updated (gpointer);
+
 #endif /* OVIRT_VIEWER_INTERNAL_H */
diff --git a/main.c b/main.c
index 0425128..b4a3607 100644 (file)
--- a/main.c
+++ b/main.c
@@ -550,3 +550,13 @@ main_status_error (gpointer _str)
 
   return FALSE;
 }
+
+/* The WUI thread has updated the vm list. */
+gboolean
+main_vmlist_updated (gpointer data)
+{
+  DEBUG ("vmlist updated");
+  ASSERT_IS_MAIN_THREAD ();
+
+  return FALSE;
+}
index 94631b6..8fbd930 100644 (file)
@@ -27,6 +27,8 @@
 #include <glib.h>
 #include <glib/gprintf.h>
 
+#include <libxml/parser.h>
+
 #include <curl/curl.h>
 
 #include "internal.h"
@@ -42,6 +44,7 @@ static gboolean do_connect (void);
 static gboolean do_login (void);
 static gboolean refresh_vm_list (void);
 static void parse_vmlist_from_xml (const char *xml);
+static struct vm *parse_vm_from_xml (xmlNodePtr node);
 
 /* Messages (main thread -> WUI thread only).
  *
@@ -752,7 +755,6 @@ refresh_vm_list (void)
 
   xml = write_fn_finish_capture ();
 
-  /*DEBUG ("XML from /vms =\n%s", xml);*/
   parse_vmlist_from_xml (xml);
   g_free (xml);
 
@@ -791,9 +793,9 @@ copy_vm (struct vm *vm)
 
   vm2 = g_memdup (vm, sizeof (*vm));
   vm2->description = g_strdup (vm->description);
-  vm2->state = g_strdup (vm->state);
-  vm2->uuid = g_strdup (vm->uuid);
-  vm2->mac_addr = g_strdup (vm->mac_addr);
+  vm2->state = vm->state ? g_strdup (vm->state) : NULL;
+  vm2->uuid = vm->uuid ? g_strdup (vm->uuid) : NULL;
+  vm2->mac_addr = vm->mac_addr ? g_strdup (vm->mac_addr) : NULL;
   return vm2;
 }
 
@@ -865,11 +867,198 @@ wui_thread_get_vmlist (GSList **ret)
 static void
 parse_vmlist_from_xml (const char *xml)
 {
-  
+  xmlDocPtr doc = NULL;
+  xmlNodePtr root;
+  xmlNodePtr node;
+  char *error_str;
+  GSList *new_vmlist = NULL;
+  struct vm *vm;
+
+  /*DEBUG ("XML =\n%s", xml);*/
+  ASSERT_IS_WUI_THREAD ();
+
+  /* We don't really expect that we won't be able to parse the XML ... */
+  doc = xmlParseDoc ((const xmlChar *) xml);
+  if (!doc) {
+    DEBUG ("error parsing XML document, xml =\n%s", xml);
+    error_str = g_strdup ("error parsing XML document from remote server");
+    g_idle_add (main_status_error, error_str);
+    goto done;
+  }
+
+  root = xmlDocGetRootElement (doc);
+  if (!root) {
+    DEBUG ("XML document was empty");
+    error_str = g_strdup ("XML document was empty");
+    g_idle_add (main_status_error, error_str);
+    goto done;
+  }
+
+  /* We expect the root element will be either "nil-classes"
+   * or "vms", with the former indicating an empty list of VMs.
+   */
+  if (xmlStrcmp (root->name, (const xmlChar *) "nil-classes") == 0) {
+    g_static_mutex_lock (&vmlist_mutex);
+    vmlist_valid = TRUE;
+    free_vmlist (vmlist);
+    vmlist = NULL;
+    g_static_mutex_unlock (&vmlist_mutex);
+
+    /* Signal to the main UI thread that the list has been updated. */
+    g_idle_add (main_vmlist_updated, NULL);
+
+    goto done;
+  }
 
+  if (xmlStrcmp (root->name, (const xmlChar *) "vms") != 0) {
+    DEBUG ("unexpected root node in XML document, xml =\n%s", xml);
+    error_str = g_strdup ("unexpected root node in XML document");
+    g_idle_add (main_status_error, error_str);
+    goto done;
+  }
 
+  /* The document is <vms> with a list of <vm> elements which
+   * we process in turn.
+   */
+  for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
+    if (xmlStrcmp (node->name, (const xmlChar *) "vm") == 0) {
+      vm = parse_vm_from_xml (node);
+      if (!vm) {
+       error_str = g_strdup ("could not parse <vm> element");
+       g_idle_add (main_status_error, error_str);
+
+       free_vmlist (new_vmlist);
+       goto done;
+      }
+      new_vmlist = g_slist_prepend (new_vmlist, vm);
+    }
+  }
 
+  /* Successfully parsed all the <vm> nodes, so swap the old and new
+   * vmlists.
+   */
+  g_static_mutex_lock (&vmlist_mutex);
+  vmlist_valid = TRUE;
+  free_vmlist (vmlist);
+  vmlist = new_vmlist;
+  g_static_mutex_unlock (&vmlist_mutex);
+
+  /* Signal that the vmlist has been updated. */
+  g_idle_add (main_vmlist_updated, NULL);
+
+ done:
+  /* Free up XML resources used before returning. */
+  if (doc) xmlFreeDoc (doc);
+}
 
+static struct vm *
+parse_vm_from_xml (xmlNodePtr node)
+{
+  xmlNodePtr p;
+  struct vm vm, *ret;
+  xmlChar *str;
+
+  memset (&vm, 0, sizeof vm);
+  vm.hostid = -1;
+  vm.id = -1;
+  vm.vnc_port = -1;
+  vm.mem_allocated = -1;
+  vm.mem_used = -1;
+  vm.vcpus_allocated = -1;
+  vm.vcpus_used = -1;
+
+  for (p = node->xmlChildrenNode; p != NULL; p = p->next) {
+    if (xmlStrcmp (p->name, (const xmlChar *) "description") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.description = g_strdup ((char *) str);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "host-id") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.hostid = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "id") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.id = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "memory-allocated") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.mem_allocated = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "memory-used") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.mem_used = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-allocated") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.vcpus_allocated = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "num-vcpus-used") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.vcpus_used = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "state") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.state = g_strdup ((char *) str);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "uuid") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.uuid = g_strdup ((char *) str);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "vnc-port") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.vnc_port = strtol ((char *) str, NULL, 10);
+       xmlFree (str);
+      }
+    }
+    else if (xmlStrcmp (p->name, (const xmlChar *) "vnic-mac-addr") == 0) {
+      str = xmlNodeGetContent (p);
+      if (str != NULL) {
+       vm.mac_addr = g_strdup ((char *) str);
+       xmlFree (str);
+      }
+    }
+  }
 
+  /* Make sure we've got the required fields. */
+  ret = NULL;
+  if (vm.description == NULL)
+    DEBUG ("required field \"description\" missing from <vm> structure");
+  else if (vm.hostid == -1)
+    DEBUG ("required field \"description\" missing from <vm> structure");
+  else if (vm.id == -1)
+    DEBUG ("required field \"description\" missing from <vm> structure");
+  else if (vm.vnc_port == -1)
+    DEBUG ("required field \"vnc-port\" missing from <vm> structure");
+  else
+    ret = g_memdup (&vm, sizeof vm);
 
+  return ret;
 }