[Ovirt-devel] [PATCH] Refactored the ovirt-identify codebase, and added NIC info during the identify phase.

Darryl L. Pierce dpierce at redhat.com
Mon Jul 21 13:25:58 UTC 2008


Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 ovirt-managed-node/ovirt-managed-node.spec         |    2 +
 ovirt-managed-node/src/Makefile                    |    6 +-
 ovirt-managed-node/src/comm.c                      |   87 +++
 ovirt-managed-node/src/debug.c                     |   48 ++
 ovirt-managed-node/src/gather.c                    |  284 +++++++++
 ovirt-managed-node/src/hal_support.c               |   65 ++
 ovirt-managed-node/src/main.c                      |  216 +++++++
 ovirt-managed-node/src/ovirt-identify-node.c       |  653 --------------------
 ovirt-managed-node/src/ovirt-identify-node.h       |  119 +++-
 ovirt-managed-node/src/protocol.c                  |  276 +++++++++
 ovirt-managed-node/src/scripts/ovirt-post          |    8 +-
 wui/src/host-browser/host-browser.rb               |   84 +++-
 wui/src/host-browser/test-host-browser-identify.rb |   42 ++-
 13 files changed, 1200 insertions(+), 690 deletions(-)
 create mode 100644 ovirt-managed-node/src/comm.c
 create mode 100644 ovirt-managed-node/src/debug.c
 create mode 100644 ovirt-managed-node/src/gather.c
 create mode 100644 ovirt-managed-node/src/hal_support.c
 create mode 100644 ovirt-managed-node/src/main.c
 delete mode 100644 ovirt-managed-node/src/ovirt-identify-node.c
 create mode 100644 ovirt-managed-node/src/protocol.c

diff --git a/ovirt-managed-node/ovirt-managed-node.spec b/ovirt-managed-node/ovirt-managed-node.spec
index 4e14b08..0cd3aa8 100644
--- a/ovirt-managed-node/ovirt-managed-node.spec
+++ b/ovirt-managed-node/ovirt-managed-node.spec
@@ -12,7 +12,9 @@ URL:            http://www.ovirt.org/
 Requires(post):  /sbin/chkconfig
 Requires(preun): /sbin/chkconfig
 BuildRequires:  libvirt-devel
+BuildRequires:  dbus-devel hal-devel
 Requires:       libvirt
+Requires:       hal
 ExclusiveArch:  %{ix86} x86_64
 
 %define app_root %{_datadir}/%{name}
diff --git a/ovirt-managed-node/src/Makefile b/ovirt-managed-node/src/Makefile
index 1991e46..d5e4093 100644
--- a/ovirt-managed-node/src/Makefile
+++ b/ovirt-managed-node/src/Makefile
@@ -17,9 +17,9 @@
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
 CC=gcc
-CFLAGS=-Wall -c -g
-LFLAGS=-lvirt
-OBJECTS=ovirt-identify-node.o
+CFLAGS=-Wall -c -g $(shell pkg-config --cflags dbus-1)
+LFLAGS=-lhal -lvirt
+OBJECTS=comm.o gather.o hal_support.o main.o protocol.o
 TARGET=ovirt-identify-node
 SOURCES=\
 	ovirt-identify-node.c
diff --git a/ovirt-managed-node/src/comm.c b/ovirt-managed-node/src/comm.c
new file mode 100644
index 0000000..a63a58d
--- /dev/null
+++ b/ovirt-managed-node/src/comm.c
@@ -0,0 +1,87 @@
+/* comm.c -- Contains communications routines.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+ssize_t saferead(int fd, char *buf, size_t count)
+{
+    ssize_t bytes,offset;
+    int len_left;
+    int done = 0;
+
+    DEBUG("Begin saferead(%d, %p, %d)\n", fd, buf, count);
+
+    offset = 0;
+    len_left = count;
+
+
+    while(!done)
+    {
+        DEBUG("Before read(%d,%p,%d)\n",fd,buf+offset,len_left);
+
+        bytes = read(fd, buf+offset, len_left);
+
+        DEBUG("After read: bytes=%d\n", bytes);
+
+        if(bytes == 0)
+        {
+            done = 1;
+        }
+        else if(bytes > 0)
+        {
+            offset += bytes;
+            len_left -= bytes;
+            done = 1;
+        }
+        else if(errno == EINTR)
+        {
+            continue;
+        }
+        else
+        {
+            done = 1;
+        }
+
+        DEBUG("End of decision loop: offset=%d, len_left=%dl, done=%d\n",offset, len_left, done);
+    }
+
+    return offset;
+}
+
+ssize_t safewrite(int fd, const void *buf, size_t count)
+{
+        size_t nwritten = 0;
+        while (count > 0) {
+                ssize_t r = write(fd, buf, count);
+
+                if (r < 0 && errno == EINTR)
+                        continue;
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return nwritten;
+                buf = (const char *)buf + r;
+                count -= r;
+                nwritten += r;
+        }
+        return nwritten;
+}
+
diff --git a/ovirt-managed-node/src/debug.c b/ovirt-managed-node/src/debug.c
new file mode 100644
index 0000000..807d88b
--- /dev/null
+++ b/ovirt-managed-node/src/debug.c
@@ -0,0 +1,48 @@
+/* debug.c -- Debugging methods.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+void debug_cpu_info(void)
+{
+    fprintf(stdout,"Node Info:\n");
+    fprintf(stdout,"     UUID: %s\n", uuid);
+    fprintf(stdout,"     Arch: %s\n", arch);
+    fprintf(stdout,"   Memory: %s\n", memsize);
+
+    t_cpu_info* current = cpu_info;
+    while(current != NULL)
+    {
+        fprintf(stdout,"\n");
+        fprintf(stdout,"     CPU Number: %s\n", current->cpu_num);
+        fprintf(stdout,"    Core Number: %s\n", current->core_num);
+        fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores);
+        fprintf(stdout,"         Vendor: %s\n", current->vendor);
+        fprintf(stdout,"          Model: %s\n", current->model);
+        fprintf(stdout,"         Family: %s\n", current->family);
+        fprintf(stdout,"    CPUID Level: %s\n", current->cpuid_level);
+        fprintf(stdout,"      CPU Speed: %s\n", current->speed);
+        fprintf(stdout,"     Cache Size: %s\n", current->cache);
+        fprintf(stdout,"      CPU Flags: %s\n", current->flags);
+
+        current = current->next;
+    }
+}
diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c
new file mode 100644
index 0000000..c7f6278
--- /dev/null
+++ b/ovirt-managed-node/src/gather.c
@@ -0,0 +1,284 @@
+/* gather.c -- Contains methods for collecting data about the system.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int init_gather(void)
+{
+    int result = 1;
+
+    hal_ctx = get_hal_ctx();
+
+    if(hal_ctx != NULL)
+    {
+        result = 0;
+    }
+
+    return result;
+}
+
+int get_uuid(void)
+{
+    const char* udi = "/org/freedesktop/Hal/devices/computer";
+    const char* key = "system.hardware.uuid";
+
+    VERBOSE("Getting system UUID.\n");
+
+    int result = 1;
+    int type;
+
+    type = libhal_device_get_property_type(hal_ctx,udi,key,&dbus_error);
+
+    if(type == LIBHAL_PROPERTY_TYPE_STRING)
+    {
+        char* value;
+
+        DEBUG("%s/%s=%d\n",udi,key,type);
+
+        value = libhal_device_get_property_string(hal_ctx,udi,key,&dbus_error);
+        snprintf(uuid,BUFFER_LENGTH,"%s",value);
+
+        DEBUG("UUID=%s\n",uuid);
+
+        result = 0;
+    }
+
+    return result;
+}
+
+/* Creates a new instance of type t_cpu_info and places it into the
+ * linked list of CPUs.
+ */
+t_cpu_info* create_cpu_info(void)
+{
+    t_cpu_info* result = calloc(1,sizeof(t_cpu_info));
+    bzero(result,sizeof(t_cpu_info));
+
+    strcpy(result->core_num,"0");
+    strcpy(result->number_of_cores,"1");
+
+    return result;
+}
+
+int get_cpu_info(void)
+{
+    int result = 1;
+    FILE* inputfd;
+    t_cpu_info* current = NULL;
+
+    /* in order to support Xen, this data will need to be gathered
+     * from libvirt rather than directly from cpuinfo
+     */
+    if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL)
+    {
+        VERBOSE("Parsing CPU information\n");
+        do
+        {
+            char buffer[255];
+            char label[BUFFER_LENGTH];
+            char value[BUFFER_LENGTH];
+
+            fgets(buffer, 255, inputfd);
+            if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0';
+
+            get_label_and_value(buffer,
+                                label,BUFFER_LENGTH,
+                                value,BUFFER_LENGTH);
+
+            DEBUG("label=\"%s\", value=\"%s\"\n", label, value);
+
+            if(strlen(label))
+            {
+                if(!strcmp(label,"processor"))
+                {
+                    VERBOSE("Starting new CPU\n");
+
+                    t_cpu_info* last = current;
+
+                    current = create_cpu_info();
+                    if(last != NULL)
+                    {
+                        last->next = current;
+                    }
+                    else
+                    {
+                        cpu_info = current;
+                    }
+
+                    COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH);
+                }
+                else
+                /* core id and number of cores is not correct on
+                 * Xen machines
+                 */
+                if(!strcmp(label,"core id"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"cpu cores"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"vendor_id"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"model"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"cpu family"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"cpuid level"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"cpu MHz"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"cache size"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH);
+                }
+                else
+                if(!strcmp(label,"flags"))
+                {
+                    COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH);
+                }
+            }
+
+        } while(!feof(inputfd));
+
+        fclose(inputfd);
+
+        result = 0;
+    }
+    else
+    {
+        VERBOSE("Unable to open /proc/cpuinfo\n");
+    }
+
+    return result;
+}
+
+/* Creates a new instance of type t_nic_info.
+ */
+t_nic_info* create_nic_info(void)
+{
+    t_nic_info* result = calloc(1,sizeof(t_nic_info));
+    bzero(result,sizeof(t_nic_info));
+
+    return result;
+}
+
+/* Determines the speed of the network interface.
+ */
+void get_nic_data(char* nic,t_nic_info* nic_info)
+{
+    char*              interface;
+    struct ifreq       ifr;
+    int                sockfd;
+    struct ethtool_cmd ecmd;
+
+    interface = libhal_device_get_property_string(hal_ctx,nic,"net.interface",
+                                                  &dbus_error);
+    bzero(&ifr,sizeof(struct ifreq));
+
+    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+    if(sockfd >= 0)
+    {
+        int bandwidth;
+
+        ifr.ifr_addr.sa_family = AF_INET;
+        strncpy(ifr.ifr_name,interface,IFNAMSIZ-1);
+
+        ioctl(sockfd, SIOCETHTOOL, &ifr);
+        close(sockfd);
+
+        bandwidth = 10;
+        if (ecmd.supported & SUPPORTED_10000baseT_Full)
+            bandwidth = 10000;
+        else if (ecmd.supported & SUPPORTED_2500baseX_Full)
+            bandwidth = 2500;
+        else if (ecmd.supported & (SUPPORTED_1000baseT_Half|SUPPORTED_1000baseT_Full))
+            bandwidth = 1000;
+        else if (ecmd.supported & (SUPPORTED_100baseT_Half|SUPPORTED_100baseT_Full))
+            bandwidth = 100;
+        else if (ecmd.supported & (SUPPORTED_10baseT_Half|SUPPORTED_10baseT_Full))
+            bandwidth = 10;
+
+        snprintf(nic_info->bandwidth,BUFFER_LENGTH,"%d",bandwidth);
+    }
+}
+
+int get_nic_info(void)
+{
+    int         result  = 0;
+    t_nic_info* current = NULL;
+    t_nic_info* last    = NULL;
+
+    char** nics;
+    int    num_results;
+    int    index;
+
+    nics = libhal_find_device_by_capability(hal_ctx,"net",
+            &num_results,&dbus_error);
+
+    DEBUG("Found %d NICs\n", num_results);
+
+    for(index = 0;index < num_results;index++)
+    {
+        char* nic = nics[index];
+
+        VERBOSE("Starting new NIC.\n");
+
+        if(current != NULL)
+        {
+            last       = current;
+            current    = create_nic_info();
+            last->next = current;
+        }
+        else
+        {
+            nic_info = current = create_nic_info();
+        }
+
+        snprintf(current->mac_address,BUFFER_LENGTH,"%s",
+            libhal_device_get_property_string(hal_ctx,nic,"net.address",
+                &dbus_error));
+        get_nic_data(nic,current);
+
+        DEBUG("NIC details: MAC:%s, speed:%s, IP:%s\n",
+            nic_info->mac_address, nic_info->bandwidth,nic_info->ip_address);
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/hal_support.c b/ovirt-managed-node/src/hal_support.c
new file mode 100644
index 0000000..58ee29b
--- /dev/null
+++ b/ovirt-managed-node/src/hal_support.c
@@ -0,0 +1,65 @@
+/* hal_support.c -- Interfaces with the HAL libraries.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+DBusConnection* dbus_connection;
+DBusError       dbus_error;
+
+LibHalContext* get_hal_ctx(void)
+{
+    LibHalContext* result = NULL;
+    LibHalContext* ctx;
+
+    ctx = libhal_ctx_new();
+    if(ctx != NULL)
+    {
+        dbus_error_init(&dbus_error);
+        dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM,&dbus_error);
+
+        if(!dbus_error_is_set(&dbus_error))
+        {
+            libhal_ctx_set_dbus_connection(ctx,dbus_connection);
+
+            if(libhal_ctx_init(ctx,&dbus_error))
+            {
+                result = ctx;
+            }
+            else
+            {
+                fprintf(stderr,"Failed to initial libhal context: %s : %s\n",
+                    dbus_error.name, dbus_error.message);
+            }
+        }
+        else
+        {
+            fprintf(stderr,"Unable to connect to system bus: %s : %s\n",
+                dbus_error.name, dbus_error.message);
+            dbus_error_free(&dbus_error);
+        }
+    }
+    else
+    {
+        fprintf(stderr,"Unable to initialize HAL context.\n");
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/main.c b/ovirt-managed-node/src/main.c
new file mode 100644
index 0000000..29e08a5
--- /dev/null
+++ b/ovirt-managed-node/src/main.c
@@ -0,0 +1,216 @@
+/* identify-node -- Main entry point for the identify-node utility.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int debug   = 0;
+int verbose = 0;
+int testing = 0;
+
+char arch[BUFFER_LENGTH];
+char uuid[BUFFER_LENGTH];
+char memsize[BUFFER_LENGTH];
+char numcpus[BUFFER_LENGTH];
+char cpuspeed[BUFFER_LENGTH];
+char *hostname;
+int  hostport = -1;
+int  socketfd;
+t_cpu_info* cpu_info;
+t_nic_info* nic_info;
+
+LibHalContext* hal_ctx;
+
+int main(int argc,char** argv)
+{
+    int result = 1;
+    virConnectPtr connection;
+    virNodeInfo info;
+
+    fprintf(stdout,"Sending managed node details to server.\n");
+
+    if(!config(argc,argv))
+    {
+        VERBOSE("Connecting to libvirt.\n");
+
+        connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL);
+
+        DEBUG("connection=%p\n",connection);
+
+        if(connection)
+        {
+            VERBOSE("Retrieving node information.\n");
+            if(!virNodeGetInfo(connection,&info))
+            {
+                snprintf(arch, BUFFER_LENGTH, "%s", info.model);
+                snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory);
+
+                cpu_info = NULL;
+                nic_info = NULL;
+
+                if(!init_gather() && !get_uuid() && !get_cpu_info() && !get_nic_info())
+                {
+                    if(!start_conversation() && !send_details() && !end_conversation())
+                    {
+                        fprintf(stdout,"Finished!\n");
+                        result = 0;
+                    }
+                }
+                else
+                {
+                    VERBOSE("Failed to get CPU info.\n");
+                }
+            }
+            else
+            {
+                VERBOSE("Failed to get node info.\n");
+            }
+        }
+        else
+        {
+            VERBOSE("Could not connect to libvirt.\n");
+        }
+    }
+    else
+    {
+        usage();
+    }
+
+    return result;
+}
+
+int config(int argc,char** argv)
+{
+    int result = 0;
+    int option;
+
+    while((option = getopt(argc,argv,"s:p:dvth")) != -1)
+    {
+        DEBUG("Processing argument: %c (optarg:%s)\n",option,optarg);
+
+        switch(option)
+        {
+            case 's': hostname = optarg; break;
+            case 'p': hostport = atoi(optarg); break;
+            case 't': testing  = 1; break;
+            case 'd': debug    = 1; break;
+            case 'v': verbose  = 1; break;
+            case 'h':
+            // fall thru
+            default : result   = 1; break;
+        }
+    }
+
+    // verify that required options are provided
+    if(hostname == NULL || strlen(hostname) == 0)
+    {
+        fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n");
+        result = 1;
+    }
+
+    if(hostport <= 0)
+    {
+        fprintf(stderr,"ERROR: The server port is required. (-p [port])\n");
+        result = 1;
+    }
+
+    return result;
+}
+
+void usage()
+{
+    fprintf(stdout,"\n");
+    fprintf(stdout,"Usage: ovirt-identify [OPTION]\n");
+    fprintf(stdout,"\n");
+    fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n");
+    fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n");
+    fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n");
+    fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n");
+    fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n");
+    fprintf(stdout,"\n");
+}
+
+void get_label_and_value(char* text,
+                         char* label, size_t label_length,
+                         char* value, size_t value_length)
+{
+    int   offset  = 0;
+    int   which   = 0; /* 0 = label, 1 = value */
+    char* current = text;
+
+    /* iterate through the text supplied and find where the
+     * label ends with a colon, then copy that into the supplied
+     * label buffer and trim any trailing spaces
+     */
+
+    while(current != NULL && *current != '\0')
+    {
+        /* if we're on the separator, then switch modes and reset
+         * the offset indicator, otherwise just process the character
+         */
+        if(which == 0 && *current == ':')
+        {
+            which  = 1;
+            offset = 0;
+        }
+        else
+        {
+            char* buffer = (which == 0 ? label : value);
+            int   length = (which == 0 ? label_length : value_length);
+
+            /* only copy if we're past the first character and it's not
+             * a space
+             */
+            if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1))
+            {
+                buffer[offset++] = *current;
+                buffer[offset]   = 0;
+            }
+        }
+
+        current++;
+    }
+
+    /* now trim all trailing spaces from the values */
+    while(label[strlen(label) - 1 ] == 9)
+        label[strlen(label) - 1] = 0;
+    while(value[strlen(value) - 1] == 9)
+        value[strlen(value) - 1] = 0;
+}
+
+int get_text(const char *const expected)
+{
+    int result = 1;
+    int received;
+    char buffer[BUFFER_LENGTH];
+    bzero(buffer,BUFFER_LENGTH);
+
+    VERBOSE( "Looking to receive %s\n", expected);
+
+    received = saferead(socketfd, buffer, BUFFER_LENGTH);
+
+    buffer[received - 1] = 0;
+
+    VERBOSE("Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received);
+
+    result = strcmp(expected,buffer);
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/ovirt-identify-node.c b/ovirt-managed-node/src/ovirt-identify-node.c
deleted file mode 100644
index f114d81..0000000
--- a/ovirt-managed-node/src/ovirt-identify-node.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/* identify-node -- Main entry point for the identify-node utility.
- *
- * Copyright (C) 2008 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce at redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301, USA.  A copy of the GNU General Public License is
- * also available at http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libvirt/libvirt.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "ovirt-identify-node.h"
-
-int main(int argc,char** argv)
-{
-    int result = 1;
-    virConnectPtr connection;
-    virNodeInfo info;
-
-    fprintf(stdout,"Sending managed node details to server.\n");
-
-    if(!config(argc,argv))
-    {
-        if(verbose)  fprintf(stdout,"Connecting to libvirt.\n");
-
-        connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL);
-
-        if(debug) fprintf(stderr,"connection=%p\n",connection);
-
-        if(connection)
-        {
-            if(verbose) fprintf(stdout,"Getting hostname: %s\n", uuid);
-            if(!strlen(uuid)) gethostname(uuid,sizeof uuid);
-
-            if(verbose) fprintf(stdout,"Retrieving node information.\n");
-            if(!virNodeGetInfo(connection,&info))
-            {
-                snprintf(arch, BUFFER_LENGTH, "%s", info.model);
-                snprintf(memsize, BUFFER_LENGTH, "%ld", info.memory);
-
-                cpu_info = NULL;
-
-                if(!get_cpu_info())
-                {
-                    if(verbose) fprintf(stdout, "Getting CPU info.\n");
-
-                    if(debug)
-                    {
-                        fprintf(stdout,"Node Info:\n");
-                        fprintf(stdout,"     UUID: %s\n", uuid);
-                        fprintf(stdout,"     Arch: %s\n", arch);
-                        fprintf(stdout,"   Memory: %s\n", memsize);
-
-                        t_cpu_info* current = cpu_info;
-                        while(current != NULL)
-                        {
-                            fprintf(stdout,"\n");
-                            fprintf(stdout,"     CPU Number: %s\n", current->cpu_num);
-                            fprintf(stdout,"    Core Number: %s\n", current->core_num);
-                            fprintf(stdout,"Number of Cores: %s\n", current->number_of_cores);
-                            fprintf(stdout,"         Vendor: %s\n", current->vendor);
-                            fprintf(stdout,"          Model: %s\n", current->model);
-                            fprintf(stdout,"         Family: %s\n", current->family);
-                            fprintf(stdout,"    CPUID Level: %s\n", current->cpuid_level);
-                            fprintf(stdout,"      CPU Speed: %s\n", current->speed);
-                            fprintf(stdout,"     Cache Size: %s\n", current->cache);
-                            fprintf(stdout,"      CPU Flags: %s\n", current->flags);
-
-                            current = current->next;
-                        }
-                    }
-
-                    if(verbose) fprintf(stdout, "Retrieved node information.\n");
-
-                    if(!start_conversation() && !send_details() && !end_conversation())
-                    {
-                        fprintf(stdout,"Finished!\n");
-                        result = 0;
-                    }
-                }
-                else
-                {
-                    if(verbose) fprintf(stderr,"Failed to get CPU info.\n");
-                }
-            }
-            else
-            {
-                if(verbose) fprintf(stderr,"Failed to get node info.\n");
-            }
-        }
-        else
-        {
-            if(verbose) fprintf(stderr,"Could not connect to libvirt.\n");
-        }
-    }
-    else
-    {
-        usage();
-    }
-
-    return result;
-}
-
-int config(int argc,char** argv)
-{
-    int result = 0;
-    int option;
-
-    while((option = getopt(argc,argv,"s:p:u:dvth")) != -1)
-    {
-        if(debug) fprintf(stdout,"Processing argument: %c (optarg:%s)\n",option,optarg);
-
-        switch(option)
-        {
-            case 's': hostname = optarg; break;
-            case 'p': hostport = atoi(optarg); break;
-            case 'u': snprintf(uuid,VIR_UUID_BUFLEN,"%s",optarg); break;
-            case 't': testing  = 1; break;
-            case 'd': debug    = 1; break;
-            case 'v': verbose  = 1; break;
-            case 'h':
-            // fall thru
-            default : result   = 1; break;
-        }
-    }
-
-    // verify that required options are provided
-    if(hostname == NULL || strlen(hostname) == 0)
-    {
-        fprintf(stderr,"ERROR: The server name is required. (-s [hostname])\n");
-        result = 1;
-    }
-
-    if(hostport <= 0)
-    {
-        fprintf(stderr,"ERROR: The server port is required. (-p [port])\n");
-        result = 1;
-    }
-
-    return result;
-}
-
-void usage()
-{
-    fprintf(stdout,"\n");
-    fprintf(stdout,"Usage: ovirt-identify [OPTION]\n");
-    fprintf(stdout,"\n");
-    fprintf(stdout,"\t-s [server]\t\tThe remote server's hostname.\n");
-    fprintf(stdout,"\t-p [port]\t\tThe remote server's port.\n");
-    fprintf(stdout,"\t-d\t\tDisplays debug information during execution.\n");
-    fprintf(stdout,"\t-v\t\tDisplays verbose information during execution.\n");
-    fprintf(stdout,"\t-h\t\tDisplays this help information and then exits.\n");
-    fprintf(stdout,"\n");
-}
-
-int start_conversation(void)
-{
-    int result = 1;
-
-    if(verbose || debug) fprintf(stdout,"Starting conversation with %s:%d.\n",hostname,hostport);
-
-    if(!create_connection())
-    {
-        if(debug || verbose) fprintf(stdout,"Connected.\n");
-
-        if (!get_text("HELLO?"))
-        {
-            if(verbose) fprintf(stdout,"Checking for handshake.\n");
-
-            if(!send_text("HELLO!"))
-            {
-                if(verbose) fprintf(stdout,"Handshake received. Starting conversation.\n");
-
-                if(!get_text("MODE?"))
-                {
-                    if(verbose) fprintf(stdout,"Shifting to IDENTIFY mode.\n");
-
-                    if(!send_text("IDENTIFY")) result = 0;
-                }
-                else
-                {
-                    if(verbose) fprintf(stderr,"Was not asked for a mode.\n");
-                }
-            }
-        }
-        else
-        {
-            if(verbose) fprintf(stderr,"Did not receive a proper handshake.\n");
-        }
-    }
-
-    else
-    {
-        if(verbose) fprintf(stderr,"Did not get a connection.\n");
-    }
-
-    if(debug) fprintf(stdout,"start_conversation: result=%d\n", result);
-
-    return result;
-}
-
-int send_value(char* label,char* value)
-{
-    char buffer[BUFFER_LENGTH];
-    int result = 1;
-    char expected[BUFFER_LENGTH];
-
-    snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value);
-
-    if(!send_text(buffer))
-    {
-        snprintf(expected, BUFFER_LENGTH, "ACK %s", label);
-
-        if(verbose) fprintf(stdout,"Expecting \"%s\"\n", expected);
-
-        result = get_text(expected);
-    }
-
-    return result;
-}
-
-int send_details(void)
-{
-    int result = 1;
-
-    if(verbose) fprintf(stdout,"Sending node details.\n");
-
-    if (!get_text("INFO?"))
-    {
-        if((!send_value("ARCH",     arch))     &&
-           (!send_value("UUID",     uuid))     &&
-           (!send_value("MEMSIZE",  memsize))  &&
-           (!send_cpu_details()))
-        {
-            if(!send_text("ENDINFO")) result = 0;
-        }
-    }
-    else
-    {
-        if(verbose) fprintf(stdout,"Was not interrogated for hardware info.\n");
-    }
-
-    return result;
-}
-
-int send_cpu_details(void)
-{
-    int result = 1;
-    t_cpu_info* current = cpu_info;
-
-    while(current != NULL)
-    {
-        send_text("CPU");
-
-        if(!(get_text("CPUINFO?"))                              &&
-           (!send_value("CPUNUM",current->cpu_num))             &&
-           (!send_value("CORENUM",current->core_num))           &&
-           (!send_value("NUMCORES",current->number_of_cores))   &&
-           (!send_value("VENDOR",current->vendor))              &&
-           (!send_value("MODEL",current->model))                &&
-           (!send_value("FAMILY",current->family))              &&
-           (!send_value("CPUIDLVL",current->cpuid_level))       &&
-           (!send_value("SPEED",current->speed))                &&
-           (!send_value("CACHE", current->cache))               &&
-           (!send_value("FLAGS", current->flags)))
-            {
-                send_text("ENDCPU");
-                result = get_text("ACK CPU");
-            }
-
-        current = current->next;
-    }
-
-
-    return result;
-}
-
-int end_conversation(void)
-{
-    int result = 0;
-
-    if(debug || verbose) fprintf(stdout,"Ending conversation.\n");
-
-    send_text("ENDINFO");
-
-    close(socketfd);
-
-    return result;
-}
-
-void get_label_and_value(char* text,
-                         char* label, size_t label_length,
-                         char* value, size_t value_length)
-{
-    int   offset  = 0;
-    int   which   = 0; /* 0 = label, 1 = value */
-    char* current = text;
-
-    /* iterate through the text supplied and find where the
-     * label ends with a colon, then copy that into the supplied
-     * label buffer and trim any trailing spaces
-     */
-
-    while(current != NULL && *current != '\0')
-    {
-        /* if we're on the separator, then switch modes and reset
-         * the offset indicator, otherwise just process the character
-         */
-        if(which == 0 && *current == ':')
-        {
-            which  = 1;
-            offset = 0;
-        }
-        else
-        {
-            char* buffer = (which == 0 ? label : value);
-            int   length = (which == 0 ? label_length : value_length);
-
-            /* only copy if we're past the first character and it's not
-             * a space
-             */
-            if((offset > 0 || (*current != 9 && *current != ' ')) && offset < (length - 1))
-            {
-                buffer[offset++] = *current;
-                buffer[offset]   = 0;
-            }
-        }
-
-        current++;
-    }
-
-    /* now trim all trailing spaces from the values */
-    while(label[strlen(label) - 1 ] == 9)
-        label[strlen(label) - 1] = 0;
-    while(value[strlen(value) - 1] == 9)
-        value[strlen(value) - 1] = 0;
-}
-
-int get_cpu_info(void)
-{
-    int result = 1;
-    FILE* inputfd;
-    t_cpu_info* current = NULL;
-
-    if(( inputfd = fopen("/proc/cpuinfo","rb")) != NULL)
-    {
-        if(verbose) fprintf(stdout,"Parsing CPU information\n");
-        do
-        {
-            char buffer[255];
-            char label[BUFFER_LENGTH];
-            char value[BUFFER_LENGTH];
-
-            fgets(buffer, 255, inputfd);
-            if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0';
-
-            get_label_and_value(buffer,
-                                label,BUFFER_LENGTH,
-                                value,BUFFER_LENGTH);
-
-            if(debug)
-                fprintf(stdout,"label=\"%s\", value=\"%s\"\n", label, value);
-
-            if(strlen(label))
-            {
-                if(!strcmp(label,"processor"))
-                {
-                    if(debug || verbose)
-                        fprintf(stdout,"Starting new CPU\n");
-
-                    t_cpu_info* last = current;
-
-                    current = create_cpu_info();
-                    if(last != NULL)
-                    {
-                        last->next = current;
-                    }
-                    else
-                    {
-                        cpu_info = current;
-                    }
-
-                    COPY_VALUE_TO_BUFFER(value,current->cpu_num,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"core id"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->core_num,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu cores"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->number_of_cores,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"vendor_id"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->vendor,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"model"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->model,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu family"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->family,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpuid level"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->cpuid_level,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cpu MHz"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->speed,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"cache size"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->cache,BUFFER_LENGTH);
-                }
-                else
-                if(!strcmp(label,"flags"))
-                {
-                    COPY_VALUE_TO_BUFFER(value,current->flags,BUFFER_LENGTH);
-                }
-            }
-
-        } while(!feof(inputfd));
-
-        fclose(inputfd);
-
-        result = 0;
-    }
-    else
-    {
-        if(verbose) fprintf(stderr,"Unable to open /proc/cpuinfo\n");
-    }
-
-    return result;
-}
-
-t_cpu_info* create_cpu_info(void)
-{
-    t_cpu_info* result = calloc(1,sizeof(t_cpu_info));
-    bzero(result,sizeof(t_cpu_info));
-
-    strcpy(result->core_num,"0");
-    strcpy(result->number_of_cores,"1");
-
-
-    return result;
-}
-
-ssize_t safewrite(int fd, const void *buf, size_t count)
-{
-        size_t nwritten = 0;
-        while (count > 0) {
-                ssize_t r = write(fd, buf, count);
-
-                if (r < 0 && errno == EINTR)
-                        continue;
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return nwritten;
-                buf = (const char *)buf + r;
-                count -= r;
-                nwritten += r;
-        }
-        return nwritten;
-}
-
-int send_text(char* text)
-{
-    int result = 1;
-    int sent;
-
-    if(verbose) fprintf(stdout,"Sending: \"%s\"\n", text);
-
-    sent = safewrite(socketfd, text, strlen(text));
-    sent += safewrite(socketfd, "\n", 1);
-
-    if(sent >= 0)
-    {
-        if(debug) fprintf(stdout,"Sent %d bytes total.\n", sent);
-
-        result = 0;
-    }
-
-    return result;
-}
-
-int saferead(int fd, char *buf, size_t count)
-{
-    ssize_t bytes,offset;
-    int len_left;
-    int done = 0;
-
-    if(debug) fprintf(stdout,"Begin saferead(%d, %p, %ld)\n", fd, buf, count);
-
-    offset = 0;
-    len_left = count;
-
-
-    while(!done)
-    {
-        if(debug) fprintf(stdout,"Before read(%ld,%p,%ld)\n",fd,buf+offset,len_left);
-
-        bytes = read(fd, buf+offset, len_left);
-
-        if(debug) fprintf(stdout,"After read: bytes=%ld\n", bytes);
-
-        if(bytes == 0)
-        {
-            done = 1;
-        }
-        else if(bytes > 0)
-        {
-            offset += bytes;
-            len_left -= bytes;
-            done = 1;
-        }
-        else if(errno == EINTR)
-        {
-            continue;
-        }
-        else
-        {
-            done = 1;
-        }
-
-        if(debug) fprintf(stdout,"End of decision loop: offset=%ld, len_left=%dl, done=%d\n",offset, len_left, done);
-    }
-
-    return offset;
-}
-
-int get_text(const char *const expected)
-{
-    int result = 1;
-    int received;
-    char buffer[BUFFER_LENGTH];
-    bzero(buffer,BUFFER_LENGTH);
-
-    if(verbose) fprintf(stdout, "Looking to receive %s\n", expected);
-
-    received = saferead(socketfd, buffer, BUFFER_LENGTH);
-
-    buffer[received - 1] = 0;
-
-    if(verbose) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", buffer, received);
-
-    result = strcmp(expected,buffer);
-
-    return result;
-}
-
-int create_connection(void)
-{
-    int result = 1;
-    struct addrinfo hints;
-    struct addrinfo* results;
-    char port[6];
-    struct addrinfo* rptr;
-
-    if(verbose) fprintf(stdout,"Creating the socket connection.\n");
-
-    memset(&hints, 0, sizeof(struct addrinfo));
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = 0;
-    hints.ai_protocol = 0;
-
-    if(verbose) fprintf(stdout,"Searching for host candidates.\n");
-
-    snprintf(port, 6, "%d", hostport);
-
-    if(!getaddrinfo(hostname, port, &hints, &results))
-    {
-        if(verbose) fprintf(stdout,"Got address information. Searching for a proper entry.\n");
-
-        for(rptr = results; rptr != NULL; rptr = rptr->ai_next)
-        {
-            if(debug)
-            {
-                fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n",
-                rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
-            }
-
-            socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
-
-            if(socketfd == -1)
-            {
-                continue;
-            }
-
-            if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1)
-            {
-                break;
-            }
-
-            //  invalid connection, so close it
-            if(verbose) fprintf(stdout, "Invalid connection.\n");
-            close(socketfd);
-        }
-
-        if(rptr == NULL)
-        {
-            if(verbose) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport);
-        }
-        else
-        {
-            // success
-            result = 0;
-        }
-
-        freeaddrinfo(results);
-    }
-    else
-    {
-        if(verbose) fprintf(stderr,"No hosts found. Exiting...\n");
-    }
-
-    if(debug) fprintf(stdout, "create_connection: result=%d\n", result);
-
-    return result;
-}
diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h
index 1cb1526..fd1bc0a 100644
--- a/ovirt-managed-node/src/ovirt-identify-node.h
+++ b/ovirt-managed-node/src/ovirt-identify-node.h
@@ -1,6 +1,49 @@
+/* Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
 #ifndef __OVIRT_IDENTIFY_NODE_H
 #define __OVIRT_IDENTIFY_NODE_H
 
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include <hal/libhal.h>
+
+#include <libvirt/libvirt.h>
+
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+
+#include <netinet/in.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
 #define BUFFER_LENGTH 128
 #define CPU_FLAGS_BUFFER_LENGTH 256
 
@@ -18,39 +61,71 @@ typedef struct _cpu_info {
     struct _cpu_info* next;
 } t_cpu_info;
 
-#define COPY_VALUE_TO_BUFFER(value,buffer,length) \
-    snprintf(buffer,length,"%s",value)
+typedef struct _nic_info {
+    char mac_address[BUFFER_LENGTH];
+    char bandwidth[BUFFER_LENGTH];
+    char ip_address[BUFFER_LENGTH];
+    struct _nic_info* next;
+} t_nic_info;
 
 int  config(int argc,char** argv);
 void usage(void);
 
-int start_conversation(void);
-int send_details(void);
-int send_cpu_details(void);
-int end_conversation(void);
-
 void get_label_and_value(char* text,
                          char* label,size_t label_length,
                          char* value,size_t value_length);
-t_cpu_info* create_cpu_info(void);
-int get_cpu_info(void);
 
 int send_text(char* text);
 int get_text(const char *const expected);
+
+/* comm.c */
+ssize_t saferead(int fd, char *buf, size_t count);
+ssize_t safewrite(int fd, const void *buf, size_t count);
+
+/* debug.c */
+void debug_cpu_info(void);
+
+/* gather.c */
+int init_gather(void);
+int get_uuid(void);
+int get_cpu_info(void);
+int get_nic_info(void);
+
+/* hal_support.c */
+LibHalContext* get_hal_ctx(void);
+
+/* protocol.c */
 int create_connection(void);
+int start_conversation(void);
+int send_details(void);
+int end_conversation(void);
+int send_value(char* label,char* value);
+int send_text(char* text);
+
+/* variables */
+extern int  debug;
+extern int  verbose;
+extern int  testing;
+
+extern char arch[BUFFER_LENGTH];
+extern char uuid[BUFFER_LENGTH];
+extern char memsize[BUFFER_LENGTH];
+extern char numcpus[BUFFER_LENGTH];
+extern char cpuspeed[BUFFER_LENGTH];
+extern char *hostname;
+extern int  hostport;
+extern int  socketfd;
+extern t_cpu_info* cpu_info;
+extern t_nic_info* nic_info;
 
-int debug   = 0;
-int verbose = 0;
-int testing = 0;
-
-char arch[BUFFER_LENGTH];
-char uuid[VIR_UUID_BUFLEN];
-char memsize[BUFFER_LENGTH];
-char numcpus[BUFFER_LENGTH];
-char cpuspeed[BUFFER_LENGTH];
-char *hostname;
-int  hostport = -1;
-int  socketfd;
-t_cpu_info* cpu_info;
+extern DBusConnection* dbus_connection;
+extern DBusError       dbus_error;
+extern LibHalContext*  hal_ctx;
+
+/* macros */
+#define DEBUG(arg...)   if(debug)   fprintf(stderr, ##arg)
+#define VERBOSE(arg...) if(verbose) fprintf(stdout, ##arg)
+#define COPY_VALUE_TO_BUFFER(value,buffer,length) \
+    snprintf(buffer,length,"%s",value)
 
 #endif
diff --git a/ovirt-managed-node/src/protocol.c b/ovirt-managed-node/src/protocol.c
new file mode 100644
index 0000000..111a1c1
--- /dev/null
+++ b/ovirt-managed-node/src/protocol.c
@@ -0,0 +1,276 @@
+/* protocol.c -- Manages the communication between the managed node and
+ *               the oVirt server.
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.  A copy of the GNU General Public License is
+ * also available at http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "ovirt-identify-node.h"
+
+int create_connection(void)
+{
+    int result = 1;
+    struct addrinfo hints;
+    struct addrinfo* results;
+    char port[6];
+    struct addrinfo* rptr;
+
+    VERBOSE("Creating the socket connection.\n");
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = 0;
+    hints.ai_protocol = 0;
+
+    VERBOSE("Searching for host candidates.\n");
+
+    snprintf(port, 6, "%d", hostport);
+
+    if(!getaddrinfo(hostname, port, &hints, &results))
+    {
+        VERBOSE("Got address information. Searching for a proper entry.\n");
+
+        for(rptr = results; rptr != NULL; rptr = rptr->ai_next)
+        {
+            if(debug)
+            {
+                fprintf(stdout,"Attempting connection: family=%d, socket type=%d, protocol=%d\n",
+                rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
+            }
+
+            socketfd = socket(rptr->ai_family, rptr->ai_socktype, rptr->ai_protocol);
+
+            if(socketfd == -1)
+            {
+                continue;
+            }
+
+            if(connect(socketfd, rptr->ai_addr, rptr->ai_addrlen) != -1)
+            {
+                break;
+            }
+
+            //  invalid connection, so close it
+            VERBOSE( "Invalid connection.\n");
+            close(socketfd);
+        }
+
+        if(rptr == NULL)
+        {
+            VERBOSE("Unable to connect to server %s:%d\n", hostname, hostport);
+        }
+        else
+        {
+            // success
+            result = 0;
+        }
+
+        freeaddrinfo(results);
+    }
+    else
+    {
+        VERBOSE("No hosts found. Exiting...\n");
+    }
+
+    DEBUG( "create_connection: result=%d\n", result);
+
+    return result;
+}
+
+int start_conversation(void)
+{
+    int result = 1;
+
+    VERBOSE("Starting conversation with %s:%d.\n",hostname,hostport);
+
+    if(!create_connection())
+    {
+        VERBOSE("Connected.\n");
+
+        if (!get_text("HELLO?"))
+        {
+            VERBOSE("Checking for handshake.\n");
+
+            if(!send_text("HELLO!"))
+            {
+                VERBOSE("Handshake received. Starting conversation.\n");
+
+                if(!get_text("MODE?"))
+                {
+                    VERBOSE("Shifting to IDENTIFY mode.\n");
+
+                    if(!send_text("IDENTIFY")) result = 0;
+                }
+                else
+                {
+                    VERBOSE("Was not asked for a mode.\n");
+                }
+            }
+        }
+        else
+        {
+            VERBOSE("Did not receive a proper handshake.\n");
+        }
+    }
+
+    else
+    {
+        VERBOSE("Did not get a connection.\n");
+    }
+
+    DEBUG("start_conversation: result=%d\n", result);
+
+    return result;
+}
+
+/* Transmits the CPU details to the server.
+ */
+int send_cpu_details(void)
+{
+    int result = 1;
+    t_cpu_info* current = cpu_info;
+
+    while(current != NULL)
+    {
+        send_text("CPU");
+
+        if(!(get_text("CPUINFO?"))                              &&
+           (!send_value("CPUNUM",current->cpu_num))             &&
+           (!send_value("CORENUM",current->core_num))           &&
+           (!send_value("NUMCORES",current->number_of_cores))   &&
+           (!send_value("VENDOR",current->vendor))              &&
+           (!send_value("MODEL",current->model))                &&
+           (!send_value("FAMILY",current->family))              &&
+           (!send_value("CPUIDLVL",current->cpuid_level))       &&
+           (!send_value("SPEED",current->speed))                &&
+           (!send_value("CACHE", current->cache))               &&
+           (!send_value("FLAGS", current->flags)))
+            {
+                send_text("ENDCPU");
+                result = get_text("ACK CPU");
+            }
+
+        current = current->next;
+    }
+
+
+    return result;
+}
+
+/* Transmits the NIC details to the server.
+ */
+int send_nic_details(void)
+{
+    int         result  = 1;
+    t_nic_info* current = nic_info;
+
+    while(current != NULL)
+    {
+        send_text("NIC");
+
+        if(!(get_text("NICINFO?"))                       &&
+           (!send_value("MAC", current->mac_address))    &&
+           (!send_value("BANDWIDTH",current->bandwidth)))
+           {
+               send_text("ENDNIC");
+               result = get_text("ACK NIC");
+           }
+
+        current = current->next;
+    }
+
+    return result;
+}
+
+int send_details(void)
+{
+    int result = 1;
+
+    VERBOSE("Sending node details.\n");
+
+    if (!get_text("INFO?"))
+    {
+        if((!send_value("ARCH",     arch))     &&
+           (!send_value("UUID",     uuid))     &&
+           (!send_value("MEMSIZE",  memsize))  &&
+           (!send_cpu_details() && !send_nic_details()))
+        {
+            if(!send_text("ENDINFO")) result = 0;
+        }
+    }
+    else
+    {
+        VERBOSE("Was not interrogated for hardware info.\n");
+    }
+
+    return result;
+}
+
+int end_conversation(void)
+{
+    int result = 0;
+
+    VERBOSE("Ending conversation.\n");
+
+    send_text("ENDINFO");
+
+    close(socketfd);
+
+    return result;
+}
+
+int send_value(char* label,char* value)
+{
+    char buffer[BUFFER_LENGTH];
+    int result = 1;
+    char expected[BUFFER_LENGTH];
+
+    snprintf(buffer,BUFFER_LENGTH,"%s=%s", label, value);
+
+    if(!send_text(buffer))
+    {
+        snprintf(expected, BUFFER_LENGTH, "ACK %s", label);
+
+        VERBOSE("Expecting \"%s\"\n", expected);
+
+        result = get_text(expected);
+    }
+
+    return result;
+}
+
+int send_text(char* text)
+{
+    int result = 1;
+    int sent;
+
+    VERBOSE("Sending: \"%s\"\n", text);
+
+    sent = safewrite(socketfd, text, strlen(text));
+    sent += safewrite(socketfd, "\n", 1);
+
+    if(sent >= 0)
+    {
+        DEBUG("Sent %d bytes total.\n", sent);
+
+        result = 0;
+    }
+
+    return result;
+}
diff --git a/ovirt-managed-node/src/scripts/ovirt-post b/ovirt-managed-node/src/scripts/ovirt-post
index f113b28..310a41c 100755
--- a/ovirt-managed-node/src/scripts/ovirt-post
+++ b/ovirt-managed-node/src/scripts/ovirt-post
@@ -12,14 +12,8 @@
 
 start() {
     find_srv identify tcp
-    UUID=`hal-get-property --udi \
-        /org/freedesktop/Hal/devices/computer --key system.hardware.uuid`
 
-    if [ -z $UUID ]; then
-        ovirt-identify-node -s $SRV_HOST -p $SRV_PORT
-    else
-        ovirt-identify-node -s $SRV_HOST -p $SRV_PORT -u $UUID
-    fi
+    ovirt-identify-node -s $SRV_HOST -p $SRV_PORT
 }
 
 case "$1" in
diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb
index 624661d..d209bdb 100755
--- a/wui/src/host-browser/host-browser.rb
+++ b/wui/src/host-browser/host-browser.rb
@@ -87,8 +87,8 @@ class HostBrowser
 
             break if info == "ENDINFO"
 
-            # if we got the start of a CPU details marker, then process it
-            if info == "CPU"
+            case info
+            when "CPU"
                 cpu = get_cpu_info
                 cpu_info = result['CPUINFO']
 
@@ -98,7 +98,16 @@ class HostBrowser
                 end
 
                 cpu_info << cpu
+            when "NIC"
+                nic = get_nic_info
+                nic_info = result['NICINFO']
 
+                if(nic_info == nil)
+                    nic_info = Array.new
+                    result['NICINFO'] = nic_info
+                end
+
+                nic_info << nic
             else
 
                 raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
@@ -144,6 +153,35 @@ class HostBrowser
         return result
     end
 
+    # Extracts NIC details from the managed node.
+    #
+    def get_nic_info
+        puts "Begin receiving NIC details"
+
+        result = Hash.new
+
+        @session.write("NICINFO?\n")
+
+        loop do
+            info = @session.readline.chomp
+
+            break if info == "ENDNIC"
+
+            raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
+
+            key, value = info.split("=")
+
+            puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
+            result[key] = value
+
+            @session.write("ACK #{key}\n")
+        end
+
+        @session.write("ACK NIC\n");
+
+        return result
+    end
+
     # Writes the supplied host information to the database.
     #
     def write_host_info(host_info)
@@ -151,8 +189,10 @@ class HostBrowser
         ensure_present(host_info,'ARCH')
         ensure_present(host_info,'MEMSIZE')
         ensure_present(host_info,'CPUINFO')
+        ensure_present(host_info,'NICINFO')
 
         cpu_info = host_info['CPUINFO']
+        nic_info = host_info['NICINFO']
 
         cpu_info.each do |cpu|
             ensure_present(cpu,'CPUNUM')
@@ -216,7 +256,45 @@ class HostBrowser
             host.cpus << detail
          end
 
-         host.save!
+        # Update the NIC details for this host:
+        # -if the NIC exists, then update the IP address
+        # -if the NIC does not exist, create it
+        # -any nic not in this list is deleted
+
+        puts "Updating NIC records for the node"
+        nics = Array.new
+
+        host.nics.collect do |nic|
+            found = false
+
+            nic_info.collect do |detail|
+                # if we have a match, then update the database and remove
+                # the received data to avoid creating a dupe later
+                if detail['MAC'] == nic.mac
+                    nic_info.delete(detail)
+                end
+            end
+
+            # if the record wasn't found, then remove it from the database
+            unless found
+                host.nics.delete(nic)
+                nic.destroy
+            end
+        end
+
+        # iterate over any nics left and create new records for them.
+
+        nic_info.collect do |nic|
+            puts "Creating a new nic..."
+            detail = Nic.new(
+                'mac'        => nic['MAC'],
+                'bandwidth'  => nic['BANDWIDTH'],
+                'usage_type' => 1)
+
+            host.nics << detail
+        end
+
+        host.save!
 
         return host
     end
diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb
index 4197e19..7e672ce 100755
--- a/wui/src/host-browser/test-host-browser-identify.rb
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -38,7 +38,7 @@ class TestHostBrowser < Test::Unit::TestCase
         @host_info = {}
         @host_info['UUID']     = 'node1'
         @host_info['IPADDR']   = '192.168.2.2'
-        @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com'
+        @host_info['HOSTNAME'] = 'prod.corp.com'
         @host_info['ARCH']     = 'x86_64'
         @host_info['MEMSIZE']  = '16384'
         @host_info['DISABLED'] = '0'
@@ -75,6 +75,15 @@ class TestHostBrowser < Test::Unit::TestCase
             mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
             fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
             bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
+
+        @host_info['NICINFO'] = Array.new
+        @host_info['NICINFO'][0] = {}
+        @host_info['NICINFO'][0]['MAC']       = '00:11:22:33:44:55'
+        @host_info['NICINFO'][0]['BANDWIDTH'] = '100'
+
+        @host_info['NICINFO'][1] = {}
+        @host_info['NICINFO'][1]['MAC']       = '00:77:11:77:19:65'
+        @host_info['NICINFO'][1]['BANDWIDTH'] = '100'
     end
 
     # Ensures that the server is satisfied if the remote system is
@@ -184,6 +193,15 @@ class TestHostBrowser < Test::Unit::TestCase
         assert_raise(Exception) { @browser.write_host_info(@host_info) }
     end
 
+    # Ensures that, if no NIC info was available, the server raises an
+    # exception.
+    #
+    def test_write_host_info_with_missing_nicinfo
+        @host_info['NICINFO'] = nil
+
+        assert_raise(Exception) { @browser.write_host_info(@host_info) }
+    end
+
     # Ensures the browser can properly parse the CPU details.
     #
     def test_parse_cpu_info
@@ -206,7 +224,7 @@ class TestHostBrowser < Test::Unit::TestCase
 
     # Ensures the browser can properly parse the CPU details of two CPUs.
     #
-    def test_parse_cpu_info
+    def test_parse_cpu_info_with_two_entries
         @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
 
         # CPU 0
@@ -242,4 +260,24 @@ class TestHostBrowser < Test::Unit::TestCase
         assert_not_nil info['CPUINFO'][1]['key4']
     end
 
+    # Ensures the browser can properly parse the details for a NIC.
+    #
+    def test_parse_nic_info
+        @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "NIC\n" }
+        @session.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "key1=value1\n" }
+        @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "key2=value2\n" }
+        @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "ENDNIC\n" }
+        @session.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length }
+        @session.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+        info = @browser.get_remote_info
+
+        assert_equal 3,info.keys.size, "Should contain four keys"
+        assert info.include?("NICINFO")
+    end
+
 end
-- 
1.5.5.1




More information about the ovirt-devel mailing list