[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
Darryl L. Pierce
dpierce at redhat.com
Tue Jun 17 15:24:45 UTC 2008
Incorporates feedback from others and some bugfixes. Primarily looking
for more feedback on the ovirt-identify-node util and how we can pull
details from libvirt to submit to the wui.
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
ovirt-daemons/Makefile | 38 ++
ovirt-daemons/identify-node.spec | 14 +
ovirt-daemons/ovirt-awake | 82 ++++
ovirt-daemons/ovirt-daemons.spec | 38 ++
ovirt-daemons/ovirt-identify | 46 ++
ovirt-daemons/ovirt-identify-node.c | 457 ++++++++++++++++++++
ovirt-host-creator/Makefile | 5 +-
ovirt-host-creator/common-post.ks | 179 +++-----
wui/src/host-browser/host-browser.rb | 106 +++--
wui/src/host-browser/test-host-browser-awaken.rb | 94 ++++
wui/src/host-browser/test-host-browser-identify.rb | 162 +++++++
wui/src/host-browser/test-host-browser.rb | 204 ---------
12 files changed, 1056 insertions(+), 369 deletions(-)
create mode 100644 ovirt-daemons/Makefile
create mode 100644 ovirt-daemons/identify-node.spec
create mode 100644 ovirt-daemons/ovirt-awake
create mode 100644 ovirt-daemons/ovirt-daemons.spec
create mode 100644 ovirt-daemons/ovirt-identify
create mode 100644 ovirt-daemons/ovirt-identify-node.c
create mode 100755 wui/src/host-browser/test-host-browser-awaken.rb
create mode 100755 wui/src/host-browser/test-host-browser-identify.rb
delete mode 100755 wui/src/host-browser/test-host-browser.rb
diff --git a/ovirt-daemons/Makefile b/ovirt-daemons/Makefile
new file mode 100644
index 0000000..a3eb399
--- /dev/null
+++ b/ovirt-daemons/Makefile
@@ -0,0 +1,38 @@
+# 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.
+
+CC=gcc
+CFLAGS=-Wall -c -g
+LFLAGS=-lvirt
+OBJECTS=ovirt-identify-node.o
+TARGET=ovirt-identify-node
+SPECFILE=ovirt-daemons.spec
+
+ALL: $(TARGET)
+
+.c.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -rf $(OBJECTS) $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CC) -o $@ $(OBJECTS) $(LFLAGS)
+
+rpms: $(TARGET)
+ rpmbuild -ba --rebuild $(SPECFILE)
diff --git a/ovirt-daemons/identify-node.spec b/ovirt-daemons/identify-node.spec
new file mode 100644
index 0000000..7f31db9
--- /dev/null
+++ b/ovirt-daemons/identify-node.spec
@@ -0,0 +1,14 @@
+Summary: oVirt managed node identification utility
+Name: ovirt-daemons
+
+
+
+Source1: version
+Version: %(echo `awk '{ print $1 }' %{SOURCE1}`)
+Release: %(echo `awk '{ print $2 }' %{SOURCE1}`)%{?dist}
+Source0: %{name}-%{version}.tar
+License: Fedora
+Group: Applications/System
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+URL: http://ovirt.org/
+
diff --git a/ovirt-daemons/ovirt-awake b/ovirt-daemons/ovirt-awake
new file mode 100644
index 0000000..30bf576
--- /dev/null
+++ b/ovirt-daemons/ovirt-awake
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# ovirt-awake Notifies the oVirt server that a managed node is
+# starting up.
+#
+# 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.
+
+# Source function library
+. /etc/init.d/ovirt-functions
+
+start () {
+ find-server identify tcp
+
+ connect-to-server
+
+ receive-text
+
+ if [ $REPLY == "HELLO?" ]; then
+ echo "Starting wakeup conversation."
+
+ send-text "HELLO!"
+
+ read 0<&3
+
+ if [ $REPLY == "MODE?" ]; then
+ send-text "AWAKEN"
+
+ receive-text
+
+ KEYTAB=`echo $REPLY | awk '{ print $2 }'`
+
+ if [ -n $KEYTAB ]; then
+ echo "Retrieving keytab: '$KEYTAB'"
+
+ wget $KEYTAB --output-document=$KEYTAB_FILE
+ else
+ echo "No keytab to retrieve"
+ fi
+ else
+ echo "Did not get a mode request."
+ fi
+ else
+ echo "Did not get a proper startup marker."
+ fi
+
+ echo "Disconnecting."
+
+ disconnect-from-server
+}
+
+case "$1" in
+ start)
+ KEYTAB_FILE=$2
+ SERVER=$3
+ PORT=$4
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
diff --git a/ovirt-daemons/ovirt-daemons.spec b/ovirt-daemons/ovirt-daemons.spec
new file mode 100644
index 0000000..eae83cc
--- /dev/null
+++ b/ovirt-daemons/ovirt-daemons.spec
@@ -0,0 +1,38 @@
+Summary: oVirt managed node daemons.
+Name: oVirt-daemons
+Version: 1.0.0
+Release: 1%{?dist}
+Group: Applications/System
+License: Fedora
+BuildRequires: libvirt-devel
+
+%description
+Provides the daemons required to interact with the oVirt management
+system.
+
+
+%prep
+
+
+%build
+
+
+%install
+
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+install -m755 ovirt-identify-node $RPM_BUILD_ROOT/sbin
+install -m755 ovirt-awake $RPM_BUILD_ROOT/sbin
+install -m755 ovirt-identify $RPM_BUILD_ROOT/sbin
+
+
+%clean
+
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+/sbin/ovirt-identify-node
+/sbin/ovirt-awake
+/sbin/ovirt-identify
diff --git a/ovirt-daemons/ovirt-identify b/ovirt-daemons/ovirt-identify
new file mode 100644
index 0000000..58651b7
--- /dev/null
+++ b/ovirt-daemons/ovirt-identify
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# ovirt-identify Submits managed node details to the central 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.
+
+# Source function library
+. /etc/init.d/ovirt-functions
+
+start () {
+ find-server identify tcp
+
+ /sbin/ovirt-identify-node -s $SERVER -p $PORT
+}
+
+case "$1" in
+ start)
+ SERVER=$2
+ PORT=$3
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
diff --git a/ovirt-daemons/ovirt-identify-node.c b/ovirt-daemons/ovirt-identify-node.c
new file mode 100644
index 0000000..3689eca
--- /dev/null
+++ b/ovirt-daemons/ovirt-identify-node.c
@@ -0,0 +1,457 @@
+/* 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>
+
+int config(int argc,char** argv);
+void usage(void);
+
+int start_conversation(void);
+int send_details(void);
+int end_conversation(void);
+
+int send_text(char* text);
+int get_text(char* response,int maxlength);
+int create_connection(void);
+
+int debug = 0;
+int verbose = 0;
+int testing = 0;
+
+#define BUFFER_LENGTH 128
+
+char arch[BUFFER_LENGTH];
+char uuid[VIR_UUID_BUFLEN];
+char memsize[BUFFER_LENGTH];
+char numcpus[BUFFER_LENGTH];
+char cpuspeed[BUFFER_LENGTH];
+char hostname[256];
+int hostport = -1;
+int socketfd;
+
+int main(int argc,char** argv)
+{
+ int result = 1;
+
+ if(!config(argc,argv))
+ {
+ fprintf(stdout,"Connecting to libvirt.\n");
+
+ virConnectPtr connection = virConnectOpenReadOnly(testing ? "test:///default" : NULL);
+
+ if(debug) fprintf(stderr,"connection=%x\n",(unsigned int )connection);
+
+ if(connection)
+ {
+ if(debug) fprintf(stdout,"Retrieving domain information.\n");
+ virDomainPtr domain = virDomainLookupByID(connection,0);
+
+ if(domain)
+ {
+ if(!virDomainGetUUIDString(domain,uuid) && debug)
+ {
+ fprintf(stdout,"Got UUID=%s\n", uuid);
+ }
+ else
+ {
+ fprintf(stderr, "Did not get UUID for node.\n");
+ }
+
+ }
+ else
+ {
+ fprintf(stderr,"Failed to connect to default domain.\n");
+ }
+
+ if(!strlen(uuid)) gethostname(uuid,sizeof uuid);
+
+ virNodeInfo info;
+
+ if(debug) fprintf(stdout,"Retrieving node information.\n");
+ if(!virNodeGetInfo(connection,&info))
+ {
+ sprintf(arch, "%s", info.model);
+ sprintf(memsize, "%ld", info.memory);
+ sprintf(numcpus, "%d", info.cpus);
+ sprintf(cpuspeed,"%d", info.mhz);
+
+ 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);
+ fprintf(stdout," # CPUs: %s\n", numcpus);
+ fprintf(stdout,"CPU Speed: %s\n", cpuspeed);
+ }
+
+ if(debug) fprintf(stdout, "Retrieved node information.\n");
+
+ if(!start_conversation() && !send_details() && !end_conversation())
+ {
+ result = 0;
+ }
+ }
+ else
+ {
+ if(debug) fprintf(stderr,"Failed to get node info.\n");
+ }
+ }
+ else
+ {
+ if(debug) 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:dvth")) != -1)
+ {
+ if(debug) fprintf(stdout,"Processing argument: %c (optarg:%s)\n",option,optarg);
+
+ switch(option)
+ {
+ case 's': strcpy(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");
+}
+
+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");
+
+ char buffer[BUFFER_LENGTH];
+
+ get_text(buffer,sizeof buffer);
+
+ if(!strcmp(buffer,"HELLO?"))
+ {
+ if(debug) fprintf(stdout,"Checking for handshake.\n");
+
+ if(!send_text("HELLO!"))
+ {
+ if(debug) fprintf(stdout,"Handshake received. Starting conversation.\n");
+
+ get_text(buffer,sizeof buffer);
+
+ if(!strcmp(buffer,"MODE?"))
+ {
+ if(debug) fprintf(stdout,"Shifting to IDENTIFY mode.\n");
+
+ if(!send_text("IDENTIFY")) result = 0;
+ }
+ else
+ {
+ if(debug) fprintf(stderr,"Was not asked for a mode.\n");
+ }
+ }
+ }
+ else
+ {
+ if(debug) fprintf(stderr,"Did not receive a proper handshake.\n");
+ }
+ }
+
+ else
+ {
+ if(debug) 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];
+
+ bzero(buffer,sizeof buffer);
+
+ sprintf(buffer,"%s=%s", label, value);
+
+ int result = 1;
+
+ if(!send_text(buffer))
+ {
+ char expected[BUFFER_LENGTH];
+
+ bzero(expected,sizeof buffer);
+ bzero(buffer,sizeof buffer);
+
+ get_text(buffer,sizeof buffer);
+
+ sprintf(expected, "ACK %s", label);
+
+ if(debug) fprintf(stdout,"Expecting \"%s\" : Received \"%s\"\n", expected, buffer);
+
+ if(!strcmp(expected,buffer))
+ {
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+int send_details(void)
+{
+ int result = 1;
+
+ fprintf(stdout,"Sending node details.\n");
+
+ char buffer[BUFFER_LENGTH];
+
+ get_text(buffer,sizeof buffer);
+
+ if(!strcmp(buffer,"INFO?"))
+ {
+ if((!send_value("ARCH", arch)) &&
+ (!send_value("UUID", uuid)) &&
+ (!send_value("NUMCPUS", numcpus)) &&
+ (!send_value("CPUSPEED", cpuspeed)) &&
+ (!send_value("MEMSIZE", memsize)))
+ {
+ if(!send_text("ENDINFO")) result = 0;
+ }
+ }
+ else
+ {
+ if(debug) fprintf(stdout,"Was not interrogated for hardware info.\n");
+ }
+
+ return result;
+}
+
+int end_conversation(void)
+{
+ int result = 0;
+
+ fprintf(stdout,"Ending conversation.\n");
+
+ send_text("ENDINFO");
+
+ close(socketfd);
+
+ 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;
+
+ if(debug || verbose) fprintf(stdout,"\"%s\" -> %s:%d\n", text, hostname, hostport);
+
+ char buffer[strlen(text) + 2];
+
+ sprintf(buffer,"%s\n",text);
+
+ // int sent = write(socketfd,buffer,strlen(buffer));
+
+ int sent = safewrite(socketfd, buffer, strlen(buffer));
+
+ if(sent >= 0)
+ {
+ if(debug) fprintf(stdout,"Sent %d bytes total.\n", sent);
+
+ result = 0;
+ }
+
+ return result;
+}
+
+int saferead(int fd, void *buf, size_t count)
+{
+ if(debug) fprintf(stdout,"Begin saferead(%d, %x, %d)\n", fd, (unsigned int)buf, count);
+
+ while (1)
+ {
+ ssize_t r = read (fd, buf, count);
+ if (r < 0 && errno == EINTR) continue;
+ return r;
+ }
+}
+
+int get_text(char* response,int maxlength)
+{
+ if(debug) fprintf(stdout,"Reading up to %d bytes from socket.\n", maxlength);
+ // int received = read(socketfd,response,maxlength);
+ int received = saferead(socketfd,response,maxlength);
+
+ response[received - 1] = 0;
+
+ if(debug) fprintf(stdout,"Received \"%s\": size=%d (trimmed ending carriage return)\n", response, received);
+
+ return received;
+}
+
+int create_connection(void)
+{
+ int result = 1;
+
+ if(debug) fprintf(stdout,"Creating the socket connection.\n");
+
+ struct addrinfo hints;
+ struct addrinfo* results;
+
+ 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(debug) fprintf(stdout,"Searching for host candidates.\n");
+
+ char port[6];
+
+ sprintf(port,"%d", hostport);
+
+ if(!getaddrinfo(hostname, port, &hints, &results))
+ {
+ if(debug) fprintf(stdout,"Got address information. Searching for a proper entry.\n");
+ struct addrinfo* rptr;
+
+ 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(debug) fprintf(stdout, "Invalid connection.\n");
+ close(socketfd);
+ }
+
+ if(rptr == NULL)
+ {
+ if(debug) fprintf(stdout,"Unable to connect to server %s:%d\n", hostname, hostport);
+ }
+ else
+ {
+ // success
+ result = 0;
+ }
+
+ freeaddrinfo(results);
+ }
+ else
+ {
+ if(debug) fprintf(stderr,"No hosts found. Exiting...\n");
+ }
+
+ if(debug) fprintf(stdout, "create_connection: result=%d\n", result);
+
+ return result;
+}
diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile
index b7d98ec..90937c5 100644
--- a/ovirt-host-creator/Makefile
+++ b/ovirt-host-creator/Makefile
@@ -39,7 +39,10 @@ clean:
repos.ks: repos.ks.in
cp repos.ks.in repos.ks
-build: ovirt-$(ARCH).ks common-install.ks common-pkgs.ks common-post.ks repos.ks
+ovirt-identify:
+ (cd ../identify-node && make)
+
+build: ovirt-$(ARCH).ks common-install.ks common-pkgs.ks common-post.ks repos.ks ovirt-identify
-rm -rf tftpboot/
./ovirt-pxe.sh > ovirt-pxe.log 2>&1
diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks
index d360736..0a1cb07 100644
--- a/ovirt-host-creator/common-post.ks
+++ b/ovirt-host-creator/common-post.ks
@@ -12,12 +12,11 @@ cat > /etc/sysconfig/iptables << \EOF
COMMIT
EOF
-echo "Writing ovirt-identify-node script"
-cat > /sbin/ovirt-identify-node << \EOF
-#!/bin/bash
-#
+echo "Writing ovirt-functions script"
+# common functions
+cat > /etc/init.d/ovirt-functions << \EOF
# Copyright (C) 2008 Red Hat, Inc.
-# Written by Chris Lalancette <clalance at redhat.com>
+# 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
@@ -34,109 +33,54 @@ cat > /sbin/ovirt-identify-node << \EOF
# MA 02110-1301, USA. A copy of the GNU General Public License is
# also available at http://www.gnu.org/copyleft/gpl.html.
-ME=$(basename "$0")
-warn() { printf "$ME: $@\n" >&2; }
-try_h() { printf "Try \`$ME -h' for more information.\n" >&2; }
-die() { warn "$@"; try_h; exit 1; }
-
-usage() {
- case $# in 1) warn "$1"; try_h; exit 1;; esac
- cat <<EOF2
-Usage: $ME [-s server] [-p port]
- -h: display this help and exit
- -p: Port number the host-browser is listening on
- -s: Hostname of the server to connect to
-EOF2
+# Determines the hostname and port for the oVirt server.
+#
+find-server() {
+ if [ -z $SERVER ]; then
+ dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname))
+ if [ $? -eq 0 ]; then
+ set _ $dnsreply; shift
+ SERVER=$4; PORT=$3
+ else
+ SERVER=; PORT=
+ fi
+ fi
+
+ if [ -z $SERVER ]; then
+ echo "No server found..."
+ exit
+ fi
}
-send_key_value() {
- echo "$1=$2" 1>&3
+# Establishes a TCP connection to the server.
+#
+connect-to-server () {
+ echo "Connecting to $SERVER:$PORT"...
- read 0<&3
- test "$REPLY" != "ACK $1" && die "Failed acknowledge of key $1"
+ exec 3<> /dev/tcp/$SERVER/$PORT
}
-############# MAIN ##################
-
-# parse our options
-while getopts ":hs:p:" flag ; do
- case "$flag" in
- h)
- usage ; exit 0
- ;;
- s)
- server=$OPTARG
- ;;
- p)
- port=$OPTARG
- ;;
- ?)
- usage "Unknown flag $flag"
- ;;
- esac
-done
+# Disconnects form the server.
+#
+disconnect-from-server () {
+ <&3-
+}
-test $(( $# - $OPTIND )) -ge 0 && usage "Too many options"
-test -z "$server" && usage "Must specify -s"
-test -z "$port" && usage "Must specify -p"
-
-# gather our information
-all_ok=0
-uuid=$(hostname -f) &&
- arch=$(uname -i) &&
- memsize=$(( $(getconf _PHYS_PAGES) * $(getconf PAGESIZE) / 1024 / 1024 )) &&
- numcpus=$(getconf _NPROCESSORS_ONLN) &&
- speed=$(sed -n "/cpu MHz/{s/.*://p;q;}" /proc/cpuinfo | tr -dc 0-9.) &&
- hostname=$(hostname -f) &&
- hypervisor="QEMU" && all_ok=1
-
-test $all_ok = 1 || die "Information gathering failed...see above"
-
-# open our connection to the remote host
-eval 'exec 3<> /dev/tcp/$server/$port' 2>err
-test $? -ne 0 && die "Connection to $server:$port failed: $(cat err)"
-
-# say hello
-read 0<&3
-test "$REPLY" != "HELLO?" && die "Expected response HELLO?, received response $REPLY"
-echo "HELLO!" 1>&3
-
-# OK, start sending our information
-read 0<&3
-test "$REPLY" != "INFO?" && die "Expected response INFO?, received response $REPLY"
-
-send_key_value "UUID" "$uuid"
-send_key_value "ARCH" "$arch"
-send_key_value "MEMSIZE" "$memsize"
-send_key_value "NUMCPUS" "$numcpus"
-send_key_value "CPUSPEED" "$speed"
-send_key_value "HOSTNAME" "$hostname"
-send_key_value "HYPERVISOR_TYPE" "$hypervisor"
-
-echo "ENDINFO" 1>&3
-
-read 0<&3
-
-test "${REPLY:0:4}" != "KTAB" && die "Expected response KTAB <filename>, received response $REPLY"
-echo "${REPLY:5}"
-EOF
-chmod +x /sbin/ovirt-identify-node
+# Sends text to the remote server.
+#
+send-text () {
+ echo "Sending: \"$1\""
+ echo "$1" 1>&3
+}
-echo "Writing ovirt-functions script"
-# common functions
-cat > /etc/init.d/ovirt-functions << \EOF
-# -*-Shell-script-*-
+# Receives text from the remote server.
+#
+receive-text () {
+ read 0<&3
-find_srv() {
- local dnsreply
- dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname))
- if [ $? -eq 0 ]; then
- set _ $dnsreply; shift
- SRV_HOST=$4; SRV_PORT=$3
- else
- SRV_HOST=; SRV_PORT=
- fi
+ echo "Received: \"$REPLY\""
}
+
EOF
echo "Writing ovirt-early init script"
@@ -168,7 +112,7 @@ configure_from_network() {
if [ "$status" = "0" ]; then
hostname $HOSTNAME
# retrieve remote config
- find_srv ovirt tcp
+ find-server ovirt tcp
printf .
if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then
wget --quiet -O - "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \
@@ -219,19 +163,26 @@ start() {
# now LVM partitions
LVMDEVS="$DEVICES `lvscan | awk '{print $2}' | tr -d \"'\"`"
- SWAPDEVS="$LVMDEVS"
+ SWAPDEVS="$LVMDEVS"
for dev in $BLOCKDEVS; do
SWAPDEVS="$SWAPDEVS `fdisk -l $dev 2>/dev/null | tr '*' ' ' \
- | awk '$5 ~ /82/ {print $1}'`"
+ | awk '$5 ~ /82/ {print $1}'`"
done
- # now check if any of these partitions are swap, and activate if so
+ # now check if any of these partitions are swap, and activate if so
for device in $SWAPDEVS; do
sig=`dd if=$device bs=1 count=10 skip=$(( $PAGESIZE - 10 )) \
- 2>/dev/null`
+ 2>/dev/null`
if [ "$sig" = "SWAPSPACE2" ]; then
swapon $device
fi
+
+ # Notify the server we're awake and retrieve a keytab file
+ krb5_tab=/etc/libvirt/krb5.tab
+ if [ ! -s $krb5_tab ]; then
+ ovirt-awake start $krb5_tab
+ fi
+
done
}
@@ -283,7 +234,7 @@ die()
start() {
echo -n $"Starting ovirt: "
- find_srv ipa tcp
+ find-server ipa tcp
krb5_conf=/etc/krb5.conf
if [ ! -s $krb5_conf ]; then
rm -f $krb5_conf
@@ -294,17 +245,9 @@ start() {
IPA_HOST=$SRV_HOST
IPA_PORT=$SRV_PORT
- find_srv identify tcp
- krb5_tab=/etc/libvirt/krb5.tab
- if [ ! -s $krb5_tab ]; then
- keytab=$(ovirt-identify-node -s $SRV_HOST -p $SRV_PORT) \
- || die "Failed to identify node"
- # FIXME this is IPA specific, host-browser should return full URL
- wget -q "http://$IPA_HOST:$IPA_PORT/config/$keytab" -O $krb5_tab \
- || die "Failed to get $krb5_tab"
- fi
+ /sbin/ovirt-identify-node start
- find_srv collectd tcp
+ find-server collectd tcp
collectd_conf=/etc/collectd.conf
if [ -f $collectd_conf.in -a $SRV_HOST -a $SRV_PORT ]; then
sed -e "s/@COLLECTD_SERVER@/$SRV_HOST/" \
@@ -415,8 +358,8 @@ LoadPlugin disk
</Plugin>
<Plugin interface>
- Interface "eth0"
- IgnoreSelected false
+ Interface "eth0"
+ IgnoreSelected false
</Plugin>
EOF
diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb
index e127ddb..3e242cf 100755
--- a/wui/src/host-browser/host-browser.rb
+++ b/wui/src/host-browser/host-browser.rb
@@ -1,5 +1,5 @@
#!/usr/bin/ruby -Wall
-#
+#
# Copyright (C) 2008 Red Hat, Inc.
# Written by Darryl L. Pierce <dpierce at redhat.com>
#
@@ -41,7 +41,7 @@ class HostBrowser
attr_accessor :logfile
attr_accessor :keytab_dir
attr_accessor :keytab_filename
-
+
def initialize(session)
@session = session
@log_prefix = "[#{session.peeraddr[3]}] "
@@ -51,19 +51,31 @@ class HostBrowser
# Ensures the conversation starts properly.
#
def begin_conversation
- puts "#{@log_prefix} Begin conversation"
+ puts "#{@log_prefix} Begin conversation" unless defined?(TESTING)
@session.write("HELLO?\n")
response = @session.readline.chomp
raise Exception.new("received #{response}, expected HELLO!") unless response == "HELLO!"
end
+ # Retrieves the mode request from the remote system.
+ #
+ def get_mode
+ puts "#{@log_prefix} Determining the runtime mode." unless defined?(TESTING)
+ @session.write("MODE?\n")
+ response = @session.readline.chomp
+ puts "#{@log_prefix} MODE=#{response}" unless defined?(TESTING)
+
+ response
+ end
+
# Requests node information from the remote system.
#
def get_remote_info
- puts "#{@log_prefix} Begin remote info collection"
+ puts "#{@log_prefix} Begin remote info collection" unless defined?(TESTING)
result = {}
- result['IPADDR'] = @session.peeraddr[3]
+ result['HOSTNAME'] = @session.peeraddr[2]
+ result['IPADDR'] = @session.peeraddr[3]
@session.write("INFO?\n")
loop do
@@ -75,9 +87,9 @@ class HostBrowser
key, value = info.split("=")
- puts "#{@log_prefix} ::Received - #{key}:#{value}"
+ puts "#{@log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
result[key] = value
-
+
@session.write("ACK #{key}\n")
end
@@ -94,13 +106,13 @@ class HostBrowser
ensure_present(host_info,'ARCH')
ensure_present(host_info,'MEMSIZE')
- puts "Searching for existing host record..."
+ puts "Searching for existing host record..." unless defined?(TESTING)
host = Host.find(:first, :conditions => ["uuid = ?", host_info['UUID']])
if host == nil
begin
- puts "Creating a new record for #{host_info['HOSTNAME']}..."
-
+ puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING)
+
Host.new(
"uuid" => host_info['UUID'],
"hostname" => host_info['HOSTNAME'],
@@ -115,7 +127,7 @@ class HostBrowser
# successfully connects to it via libvirt.
"state" => "unavailable").save
rescue Exception => error
- puts "Error while creating record: #{error.message}"
+ puts "Error while creating record: #{error.message}" unless defined?(TESTING)
end
else
host.uuid = host_info['UUID']
@@ -125,45 +137,45 @@ class HostBrowser
host.arch = host_info['ARCH']
host.memory_in_mb = host_info['MEMSIZE']
end
-
+
return host
end
- # Ends the conversation, notifying the user of the key version number.
- #
- def end_conversation(ktab)
- puts "#{@log_prefix} Ending conversation"
-
- @session.write("KTAB #{ktab}\n")
-
- response = @session.readline.chomp
-
- raise Exception.new("ERROR! Malformed response : expected ACK, got #{response}") unless response == "ACK"
-
- @session.write("BYE\n");
- end
-
# Creates a keytab if one is needed, returning the filename.
#
- def create_keytab(host_info, krb5_arg = nil)
+ def create_keytab(hostname, ipaddress, krb5_arg = nil)
krb5 = krb5_arg || Krb5.new
-
+
default_realm = krb5.get_default_realm
- libvirt_princ = 'libvirt/' + host_info['HOSTNAME'] + '@' + default_realm
- outfile = host_info['IPADDR'] + '-libvirt.tab'
+ libvirt_princ = 'libvirt/' + hostname + '@' + default_realm
+ outfile = ipaddress + '-libvirt.tab'
@keytab_filename = @keytab_dir + outfile
# TODO need a way to test this portion
unless defined? TESTING || File.exists?(@keytab_filename)
# TODO replace with Kr5Auth when it supports admin actions
- puts "Writing keytab file: #{@keytab_filename}"
+ puts "Writing keytab file: #{@keytab_filename}" unless defined?(TESTING)
kadmin_local('addprinc -randkey ' + libvirt_princ)
kadmin_local('ktadd -k ' + @keytab_filename + ' ' + libvirt_princ)
File.chmod(0644, at keytab_filename)
end
- return outfile
+ hostname = `hostname -f`.chomp
+
+ @session.write("KTAB http://#{hostname}/config/#{outfile}\n")
+
+ response = @session.readline.chomp
+
+ raise Exception.new("ERRINFO! No keytab acknowledgement") unless response == "ACK"
+ end
+
+ # Ends the conversation, notifying the user of the key version number.
+ #
+ def end_conversation
+ puts "#{@log_prefix} Ending conversation" unless defined?(TESTING)
+
+ @session.write("BYE\n");
end
private
@@ -185,35 +197,37 @@ def entry_point(server)
while(session = server.accept)
child = fork do
remote = session.peeraddr[3]
-
- puts "Connected to #{remote}"
+
+ puts "Connected to #{remote}" unless defined?(TESTING)
# This is needed because we just forked a new process
# which now needs its own connection to the database.
database_connect
-
+
begin
browser = HostBrowser.new(session)
browser.begin_conversation
- host_info = browser.get_remote_info
- browser.write_host_info(host_info)
- keytab = browser.create_keytab(host_info)
- browser.end_conversation(keytab)
+ case browser.get_mode
+ when "AWAKEN": browser.create_keytab(remote,session.peeraddr[3])
+ when "IDENTIFY": browser.write_host_info(browser.get_remote_info)
+ end
+
+ browser.end_conversation
rescue Exception => error
session.write("ERROR #{error.message}\n")
- puts "ERROR #{error.message}"
+ puts "ERROR #{error.message}" unless defined?(TESTING)
end
-
- puts "Disconnected from #{remote}"
+
+ puts "Disconnected from #{remote}" unless defined?(TESTING)
end
-
- Process.detach(child)
- end
+
+ Process.detach(child)
+ end
end
unless defined?(TESTING)
-
+
# The main entry point.
#
unless ARGV[0] == "-n"
diff --git a/wui/src/host-browser/test-host-browser-awaken.rb b/wui/src/host-browser/test-host-browser-awaken.rb
new file mode 100755
index 0000000..a5ca2e7
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-awaken.rb
@@ -0,0 +1,94 @@
+#!/usr/bin/ruby -Wall
+#
+# 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.
+
+require File.dirname(__FILE__) + '/../test/test_helper'
+require 'test/unit'
+require 'flexmock/test_unit'
+
+TESTING=true
+
+require 'host-browser'
+
+# +TestHostBrowserAwaken+
+class TestHostBrowserAwaken < Test::Unit::TestCase
+
+ def setup
+ @session = flexmock('session')
+ @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] }
+
+ @krb5 = flexmock('krb5')
+
+ @browser = HostBrowser.new(@session)
+ @browser.logfile = './unit-test.log'
+ @browser.keytab_dir = '/var/temp/'
+ end
+
+ # Ensures that the server raises an exception when it receives an
+ # improper handshake response.
+ #
+ def test_begin_conversation_with_improper_response_to_greeting
+ @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length }
+ @session.should_receive(:readline).once().returns { "SUP?" }
+
+ assert_raise(Exception) { @browser.begin_conversation }
+ end
+
+ # Ensures the server accepts a proper response from the remote system.
+ #
+ def test_begin_conversation
+ @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length }
+ @session.should_receive(:readline).once().returns { "HELLO!\n" }
+
+ assert_nothing_raised(Exception) { @browser.begin_conversation }
+ end
+
+ # Ensures that the server is satisfied if the remote system is
+ # making a wakeup call.
+ #
+ def test_get_mode_with_awaken_request
+ @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length }
+ @session.should_receive(:readline).once().returns { "AWAKEN\n" }
+
+ result = @browser.get_mode()
+
+ assert_equal "AWAKEN", result, "method did not return the right value"
+ end
+
+ # Ensures the host browser generates a keytab as expected.
+ #
+ def test_create_keytab
+ @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" }
+ servername = `hostname -f`.chomp
+ @session.should_receive(:write).with("KTAB http://#{servername}/config/127.0.0.1-libvirt.tab\n").once().returns { |request| request.length }
+ @session.should_receive(:readline).once().returns { "ACK\n" }
+
+ assert_nothing_raised(Exception) { @browser.create_keytab('localhost','127.0.0.1', at krb5) }
+ end
+
+ # Ensures that, if a keytab is present and a key version number available,
+ # the server ends the conversation by returning the key version number.
+ #
+ def test_end_conversation
+ @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length }
+
+ assert_nothing_raised(Exception) { @browser.end_conversation }
+ end
+
+end
diff --git a/wui/src/host-browser/test-host-browser-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb
new file mode 100755
index 0000000..a70884d
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -0,0 +1,162 @@
+#!/usr/bin/ruby -Wall
+#
+# 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.
+
+require File.dirname(__FILE__) + '/../test/test_helper'
+require 'test/unit'
+require 'flexmock/test_unit'
+
+TESTING=true
+
+require 'host-browser'
+
+class TestHostBrowser < Test::Unit::TestCase
+
+ def setup
+ @session = flexmock('session')
+ @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] }
+
+ @browser = HostBrowser.new(@session)
+ @browser.logfile = './unit-test.log'
+
+ # default host info
+ @host_info = {}
+ @host_info['UUID'] = 'node1'
+ @host_info['IPADDR'] = '192.168.2.2'
+ @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com'
+ @host_info['NUMCPUS'] = '3'
+ @host_info['CPUSPEED'] = '3'
+ @host_info['ARCH'] = 'x86_64'
+ @host_info['MEMSIZE'] = '16384'
+ @host_info['DISABLED'] = '0'
+ end
+
+ # Ensures that the server is satisfied if the remote system is
+ # making a wakeup call.
+ #
+ def test_get_mode_with_awaken_request
+ @session.should_receive(:write).with("MODE?\n").once().returns { |request| request.length }
+ @session.should_receive(:readline).once().returns { "IDENTIFY\n" }
+
+ result = @browser.get_mode()
+
+ assert_equal "IDENTIFY", result, "method did not return the right value"
+ end
+
+ # Ensures that, if an info field is missing a key, the server raises
+ # an exception.
+ #
+ def test_get_info_with_missing_key
+ @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+ @session.should_receive(:readline).once().returns { "=value1\n" }
+
+ assert_raise(Exception) { @browser.get_remote_info }
+ end
+
+ # Ensures that, if an info field is missing a value, the server raises
+ # an exception.
+ #
+ def test_get_info_with_missing_value
+ @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+ @session.should_receive(:readline).once().returns { "key1=\n" }
+
+ assert_raise(Exception) { @browser.get_remote_info }
+ end
+
+ # Ensures that, if the server gets a poorly formed ending statement, it
+ # raises an exception.
+ #
+ def test_get_info_with_invalid_end
+ @session.should_receive(:write).with("INFO?\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 { "ENDIFNO\n" }
+
+ assert_raise(Exception) { @browser.get_remote_info }
+ end
+
+ # Ensures that a well-formed transaction works as expected.
+ #
+ def test_get_info
+ @session.should_receive(:write).with("INFO?\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 { "ENDINFO\n" }
+
+ info = @browser.get_remote_info
+
+ assert_equal 4,info.keys.size, "Should contain two keys"
+ assert info.include?("IPADDR")
+ assert info.include?("HOSTNAME")
+ assert info.include?("key1")
+ assert info.include?("key2")
+ end
+
+ # Ensures that, if no UUID is present, the server raises an exception.
+ #
+ def test_write_host_info_with_missing_uuid
+ @host_info['UUID'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+ # Ensures that, if the hostname is missing, the server
+ # raises an exception.
+ #
+ def test_write_host_info_with_missing_hostname
+ @host_info['HOSTNAME'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+ # Ensures that, if the number of CPUs is missing, the server raises an exception.
+ #
+ def test_write_host_info_with_missing_numcpus
+ @host_info['NUMCPUS'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+ # Ensures that, if the CPU speed is missing, the server raises an exception.
+ #
+ def test_write_host_info_with_missing_cpuspeed
+ @host_info['CPUSPEED'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+ # Ensures that, if the architecture is missing, the server raises an exception.
+ #
+ def test_write_host_info_with_missing_arch
+ @host_info['ARCH'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+ # Ensures that, if the memory size is missing, the server raises an exception.
+ #
+ def test_write_host_info_info_with_missing_memsize
+ @host_info['MEMSIZE'] = nil
+
+ assert_raise(Exception) { @browser.write_host_info(@host_info) }
+ end
+
+end
diff --git a/wui/src/host-browser/test-host-browser.rb b/wui/src/host-browser/test-host-browser.rb
deleted file mode 100755
index 6f4c660..0000000
--- a/wui/src/host-browser/test-host-browser.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/usr/bin/ruby -Wall
-#
-# 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.
-
-require File.dirname(__FILE__) + '/../test/test_helper'
-require 'test/unit'
-require 'flexmock/test_unit'
-
-TESTING=true
-
-require 'host-browser'
-
-class TestHostBrowser < Test::Unit::TestCase
-
- def setup
- @session = flexmock('session')
- @session.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] }
-
- @krb5 = flexmock('krb5')
-
- @browser = HostBrowser.new(@session)
- @browser.logfile = './unit-test.log'
- @browser.keytab_dir = '/var/temp/'
-
- # default host info
- @host_info = {}
- @host_info['UUID'] = 'node1'
- @host_info['IPADDR'] = '192.168.2.2'
- @host_info['HOSTNAME'] = 'node1.ovirt.redhat.com'
- @host_info['NUMCPUS'] = '3'
- @host_info['CPUSPEED'] = '3'
- @host_info['ARCH'] = 'x86_64'
- @host_info['MEMSIZE'] = '16384'
- @host_info['DISABLED'] = '0'
- end
-
- # Ensures that the server raises an exception when it receives an
- # improper handshake response.
- #
- def test_begin_conversation_with_improper_response_to_greeting
- @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length }
- @session.should_receive(:readline).once().returns { "SUP?" }
-
- assert_raise(Exception) { @browser.begin_conversation }
- end
-
- # Ensures the server accepts a proper response from the remote system.
- #
- def test_begin_conversation
- @session.should_receive(:write).with("HELLO?\n").once().returns { |greeting| greeting.length }
- @session.should_receive(:readline).once().returns { "HELLO!\n" }
-
- assert_nothing_raised(Exception) { @browser.begin_conversation }
- end
-
- # Ensures that the server raises an exception when it receives
- # poorly formed data while exchanging system information.
- #
- def test_get_info_with_bad_handshake
- @session.should_receive(:write).with("INFO?\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 { "farkledina\n" }
-
- assert_raise(Exception) { @browser.get_remote_info }
- end
-
- # Ensures that, if an info field is missing a key, the server raises
- # an exception.
- #
- def test_get_info_with_missing_key
- @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
- @session.should_receive(:readline).once().returns { "=value1\n" }
-
- assert_raise(Exception) { @browser.get_remote_info }
- end
-
- # Ensures that, if an info field is missing a value, the server raises
- # an exception.
- #
- def test_get_info_with_missing_value
- @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
- @session.should_receive(:readline).once().returns { "key1=\n" }
-
- assert_raise(Exception) { @browser.get_remote_info }
- end
-
- # Ensures that, if the server gets a poorly formed ending statement, it
- # raises an exception.
- #
- def test_get_info_with_invalid_end
- @session.should_receive(:write).with("INFO?\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 { "ENDIFNO\n" }
-
- assert_raise(Exception) { @browser.get_remote_info }
- end
-
- # Ensures that a well-formed transaction works as expected.
- #
- def test_get_info
- @session.should_receive(:write).with("INFO?\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 { "ENDINFO\n" }
-
- info = @browser.get_remote_info
-
- assert_equal 3,info.keys.size, "Should contain two keys"
- assert info.include?("IPADDR")
- assert info.include?("key1")
- assert info.include?("key2")
- end
-
- # Ensures the host browser generates a keytab as expected.
- #
- def test_create_keytab
- @krb5.should_receive(:get_default_realm).once().returns { "ovirt-test-realm" }
-
- result = @browser.create_keytab(@host_info, at krb5)
-
- assert_equal @browser.keytab_filename, result, "Should have returned the keytab filename"
- end
-
- # Ensures that, if no UUID is present, the server raises an exception.
- #
- def test_write_host_info_with_missing_uuid
- @host_info['UUID'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if the hostname is missing, the server
- # raises an exception.
- #
- def test_write_host_info_with_missing_hostname
- @host_info['HOSTNAME'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if the number of CPUs is missing, the server raises an exception.
- #
- def test_write_host_info_with_missing_numcpus
- @host_info['NUMCPUS'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if the CPU speed is missing, the server raises an exception.
- #
- def test_write_host_info_with_missing_cpuspeed
- @host_info['CPUSPEED'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if the architecture is missing, the server raises an exception.
- #
- def test_write_host_info_with_missing_arch
- @host_info['ARCH'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if the memory size is missing, the server raises an exception.
- #
- def test_write_host_info_info_with_missing_memsize
- @host_info['MEMSIZE'] = nil
-
- assert_raise(Exception) { @browser.write_host_info(@host_info) }
- end
-
- # Ensures that, if a keytab is present and a key version number available,
- # the server ends the conversation by returning the key version number.
- #
- def test_end_conversation
- @session.should_receive(:write).with("KTAB 12345\n").once().returns { |request| request.length }
- @session.should_receive(:readline).once().returns { "ACK\n" }
- @session.should_receive(:write).with("BYE\n").once().returns { |request| request.length }
-
- assert_nothing_raised(Exception) { @browser.end_conversation(12345) }
- end
-
-end
--
1.5.4.1
More information about the ovirt-devel
mailing list