[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