Darryl L. Pierce
2008-Jun-10 21:59 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
First crack at the awaken script. I haven't finished the keytab retrieving
since I'm
not sure what the URL will be based on the hostname, et. al. But, the process is
all
in bash and no dependency on Python.
Feedback is requested. Please be gentle... :)
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
identify-node/awaken.sh | 83 ++++++++
wui/src/host-browser/host-browser.rb | 101 ++++++-----
wui/src/host-browser/test-host-browser-awaken.rb | 93 +++++++++
wui/src/host-browser/test-host-browser-identify.rb | 204 ++++++++++++++++++++
wui/src/host-browser/test-host-browser.rb | 204 --------------------
5 files changed, 437 insertions(+), 248 deletions(-)
create mode 100755 identify-node/awaken.sh
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/identify-node/awaken.sh b/identify-node/awaken.sh
new file mode 100755
index 0000000..7148f1c
--- /dev/null
+++ b/identify-node/awaken.sh
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# 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.
+
+SERVER=$1
+PORT=$2
+
+
+if [ -z $SERVER ]; then
+ dnsreply=$(dig +short -t srv _ovirt-host._tcp.$(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
+
+echo "Connecting to $SERVER:$PORT"...
+
+exec 3<> /dev/tcp/$SERVER/$PORT
+
+read 0<&3
+
+echo "Received: $REPLY"
+
+if [ $REPLY == "HELLO?" ]; then
+ echo "Starting wakeup conversation."
+
+ echo "HELLO!" 1>&3
+
+ read 0<&3
+
+ echo "Received: $REPLY"
+
+ if [ $REPLY == "MODE?" ]; then
+ echo "Sending wakeup notice."
+ echo "AWAKEN" 1>&3
+
+ read 0<&3
+
+ echo "Received: $REPLY"
+
+ KEYTAB=`echo $REPLY | awk '{ $2 }'`
+
+ if [ -n $KEYTAB ]; then
+ echo "Retrieving keytab: $KYTAB"
+
+
+ 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."
+
+<&3-
diff --git a/wui/src/host-browser/host-browser.rb
b/wui/src/host-browser/host-browser.rb
index e127ddb..d3e9d85 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,17 +51,28 @@ 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]
@session.write("INFO?\n")
@@ -75,9 +86,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 +105,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 +126,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 +136,43 @@ 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
+ @session.write("KTAB #{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 +194,39 @@ 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)
+ case browser.get_mode
+ when "AWAKEN":
browser.create_keytab(remote,session.peeraddr[3])
+ end
+ #host_info = browser.get_remote_info
+ #browser.write_host_info(host_info)
+ #keytab = browser.create_keytab(host_info)
+
browser.end_conversation(keytab)
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..a5a1bcf
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-awaken.rb
@@ -0,0 +1,93 @@
+#!/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" }
+ @session.should_receive(:write).with("KTAB
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..6f4c660
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -0,0 +1,204 @@
+#!/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
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
Darryl L. Pierce
2008-Jun-11 16:31 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
identify-node/ovirt-awake | 80 ++++++++
identify-node/ovirt-functions | 66 +++++++
wui/src/host-browser/host-browser.rb | 103 ++++++-----
wui/src/host-browser/test-host-browser-awaken.rb | 93 +++++++++
wui/src/host-browser/test-host-browser-identify.rb | 204 ++++++++++++++++++++
wui/src/host-browser/test-host-browser.rb | 204 --------------------
6 files changed, 501 insertions(+), 249 deletions(-)
create mode 100755 identify-node/ovirt-awake
create mode 100644 identify-node/ovirt-functions
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/identify-node/ovirt-awake b/identify-node/ovirt-awake
new file mode 100755
index 0000000..7f654e6
--- /dev/null
+++ b/identify-node/ovirt-awake
@@ -0,0 +1,80 @@
+#!/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
+
+ 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 '{ $2 }'`
+
+ if [ -n $KEYTAB ]; then
+ wget http://$SERVER/$KEYTAB
+ 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)
+ SERVER=$2
+ PORT=$3
+ PORT=$3
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
diff --git a/identify-node/ovirt-functions b/identify-node/ovirt-functions
new file mode 100644
index 0000000..b6c9a0a
--- /dev/null
+++ b/identify-node/ovirt-functions
@@ -0,0 +1,66 @@
+#
+# 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.
+
+# Determines the hostname and port for the oVirt server.
+#
+find-server() {
+ if [ -z $SERVER ]; then
+ dnsreply=$(dig +short -t srv _ovirt-host._tcp.$(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
+}
+
+# Establishes a TCP connection to the server.
+#
+connect-to-server () {
+ echo "Connecting to $SERVER:$PORT"...
+
+ exec 3<> /dev/tcp/$SERVER/$PORT
+}
+
+# Disconnects form the server.
+#
+disconnect-from-server () {
+ <&3-
+}
+
+# Sends text to the remote server.
+#
+send-text () {
+ echo "Sending: \"$1\""
+ echo "$1" 1>&3
+}
+
+# Receives text from the remote server.
+#
+receive-text () {
+ read 0<&3
+
+ echo "Received: \"$REPLY\""
+}
diff --git a/wui/src/host-browser/host-browser.rb
b/wui/src/host-browser/host-browser.rb
index e127ddb..8337d7b 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,17 +51,28 @@ 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]
@session.write("INFO?\n")
@@ -75,9 +86,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 +105,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 +126,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 +136,43 @@ 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
+ @session.write("KTAB #{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 +194,39 @@ 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])
+ end
+ #host_info = browser.get_remote_info
+ #browser.write_host_info(host_info)
+ #keytab = browser.create_keytab(host_info)
+
+ 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..a5a1bcf
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-awaken.rb
@@ -0,0 +1,93 @@
+#!/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" }
+ @session.should_receive(:write).with("KTAB
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..6f4c660
--- /dev/null
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -0,0 +1,204 @@
+#!/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
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
Darryl L. Pierce
2008-Jun-12 15:33 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
ovirt-host-creator/common-post.ks | 347 ++++++++++++++------
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 ------------
5 files changed, 556 insertions(+), 357 deletions(-)
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-host-creator/common-post.ks
b/ovirt-host-creator/common-post.ks
index 1cb1677..aaeb746 100644
--- a/ovirt-host-creator/common-post.ks
+++ b/ovirt-host-creator/common-post.ks
@@ -12,12 +12,15 @@ cat > /etc/sysconfig/iptables << \EOF
COMMIT
EOF
-echo "Writing ovirt-identify-node script"
-cat > /sbin/ovirt-identify-node << \EOF
+echo "Writing ovirt-awake script"
+cat > /sbin/ovirt-awake << \EOF
#!/bin/bash
#
+# ovirt-awake Notifies the oVirt server that a managed node is
+# starting up.
+#
# 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 +37,239 @@ 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
+# 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-file=$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
}
-send_key_value() {
- echo "$1=$2" 1>&3
+case "$1" in
+ start)
+ KEYTAB_FILE=$2
+ SERVER=$3
+ PORT=$4
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
+EOF
+chmod +x /sbin/ovirt-awake
+
+echo "Writing ovirt-identify script"
+cat > /sbin/ovirt-identify << \EOF
+#!/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
+
+ 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 "IDENTIFY"
+
+ receive-text
+
+ UUID=`hostname -f`
+ ARCH=`uname -i`
+ NUMCPUS=`getconf _NPROCESSORS_ONLN`
+ CPUSPEED=`grep "cpu MHz" /proc/cpuinfo | uniq | cut
-d':' -f2 | sed -e 's/^[[:space:]]*\(.*\)$/\1/' -e
's/^\(.*\)[[:space:]]*$/\1/'`
+ MEMSIZE=$((`getconf _PHYS_PAGES` * `getconf PAGESIZE` / 1024 /
1024))
- read 0<&3
- test "$REPLY" != "ACK $1" && die "Failed
acknowledge of key $1"
+ send-text "UUID=$UUID"
+ receive-text
+ send-text "ARCH=$ARCH"
+ receive-text
+ send-text "NUMCPUS=$NUMCPUS"
+ receive-text
+ send-text "CPUSPEED=$CPUSPEED"
+ receive-text
+ send-text "MEMSIZE=$MEMSIZE"
+ receive-text
+ send-text "ENDINFO"
+
+ receive-text
+
+ if [ $REPLY == "BYE" ]; then
+ echo "Success!"
+ else
+ echo "Error submitting node information..."
+ 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
}
-############# 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
+case "$1" in
+ start)
+ SERVER=$2
+ PORT=$3
+ PORT=$3
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
-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}"
+exit $RETVAL
EOF
-chmod +x /sbin/ovirt-identify-node
+chmod +x /sbin/ovirt-identify
echo "Writing ovirt-functions script"
# common functions
cat > /etc/init.d/ovirt-functions << \EOF
-# -*-Shell-script-*-
+# 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.
-find_srv() {
- local dnsreply
+# 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
- SRV_HOST=$4; SRV_PORT=$3
+ SERVER=$4; PORT=$3
else
- SRV_HOST=; SRV_PORT+ SERVER=; PORT fi
+ fi
+
+ if [ -z $SERVER ]; then
+ echo "No server found..."
+ exit
+ fi
}
+
+# Establishes a TCP connection to the server.
+#
+connect-to-server () {
+ echo "Connecting to $SERVER:$PORT"...
+
+ exec 3<> /dev/tcp/$SERVER/$PORT
+}
+
+# Disconnects form the server.
+#
+disconnect-from-server () {
+ <&3-
+}
+
+# Sends text to the remote server.
+#
+send-text () {
+ echo "Sending: \"$1\""
+ echo "$1" 1>&3
+}
+
+# Receives text from the remote server.
+#
+receive-text () {
+ read 0<&3
+
+ echo "Received: \"$REPLY\""
+}
+
EOF
echo "Writing ovirt-early init script"
@@ -168,7 +301,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
curl -s
"http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \
@@ -219,19 +352,27 @@ 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 start $krb5_tab
+ || die "Failed to notify server the node is awake"
+ fi
+
done
}
@@ -283,7 +424,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 +435,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
+ ovirt-identify 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 +548,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
Darryl L. Pierce
2008-Jun-16 14:35 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
identify-node/Makefile | 35 ++
identify-node/ovirt-identify.c | 326 ++++++++++++++++++
ovirt-host-creator/common-post.ks | 346 ++++++++++++++------
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 ------------
7 files changed, 916 insertions(+), 357 deletions(-)
create mode 100644 identify-node/Makefile
create mode 100644 identify-node/ovirt-identify.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/identify-node/Makefile b/identify-node/Makefile
new file mode 100644
index 0000000..af950b2
--- /dev/null
+++ b/identify-node/Makefile
@@ -0,0 +1,35 @@
+# 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.o
+TARGET=ovirt-identify
+
+ALL: $(TARGET)
+
+.c.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -rf $(OBJECTS) $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CC) -o $@ $(OBJECTS) $(LFLAGS)
+
diff --git a/identify-node/ovirt-identify.c b/identify-node/ovirt-identify.c
new file mode 100644
index 0000000..915b50a
--- /dev/null
+++ b/identify-node/ovirt-identify.c
@@ -0,0 +1,326 @@
+/* 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 <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 debug = 0;
+int verbose = 0;
+int testing = 0;
+
+char arch[128];
+char uuid[128];
+char memsize[128];
+char numcpus[128];
+char cpuspeed[128];
+char hostname[256];
+int hostport = -1;
+int socketfd;
+
+int main(int argc,char** argv)
+{
+ int result = 1;
+
+ if(!config(argc,argv))
+ {
+ int success = 1;
+
+ if(!testing)
+ {
+ success = 0;
+
+ fprintf(stdout,"Connecting to libvirt.\n");
+ virConnectPtr connection = virConnectOpenReadOnly(NULL);
+
+ if(debug) printf("connection=%ld\n",(long
int)connection);
+
+ if(connection)
+ {
+ virNodeInfo info;
+
+ if(debug) printf("Retrieving node information.\n");
+ if(!virNodeGetInfo(connection,&info))
+ {
+ success = 1;
+
+ gethostname(uuid,128);
+ sprintf(arch, "%s", info.model);
+ sprintf(memsize, "%ld", info.memory);
+ sprintf(numcpus, "%d", info.cpus);
+ sprintf(cpuspeed,"%d", info.mhz);
+
+ if(debug)
+ {
+ printf("Node Info:\n");
+ printf(" UUID: %s\n", uuid);
+ printf(" Arch: %s\n", arch);
+ printf(" Memory: %s\n", memsize);
+ printf(" # CPUs: %s\n", numcpus);
+ printf("CPU Speed: %s\n", cpuspeed);
+ }
+ }
+ else
+ {
+ if(debug) printf("Failed to get node info.\n");
+ }
+ }
+ else
+ {
+ if(debug) printf("Could not connect to libvirt.\n");
+ }
+ }
+ else
+ {
+ strcpy(uuid,"UUID-FOR-TESTING-PURPOSES");
+ strcpy(arch,"x86_64");
+ strcpy(memsize,"2048");
+ strcpy(numcpus,"2");
+ strcpy(cpuspeed,"2048");
+ }
+
+ if(success && !start_conversation() && !send_details()
&& !end_conversation()) result = 0;
+ }
+ 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) printf("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)
+ {
+ printf("ERROR: The server name is required. (-s
[hostname])\n");
+ result = 1;
+ }
+
+ if(hostport <= 0)
+ {
+ printf("ERROR: The server port is required. (-p [port])\n");
+ result = 1;
+ }
+
+ return result;
+}
+
+void usage()
+{
+ printf("\n");
+ printf("Usage: ovirt-identify [OPTION]\n");
+ printf("\n");
+ printf("\t-s [server]\t\tThe remote server's hostname.\n");
+ printf("\t-p [port]\t\tThe remote server's port.\n");
+ printf("\t-d\t\tDisplays debug information during execution.\n");
+ printf("\t-v\t\tDisplays verbose information during
execution.\n");
+ printf("\t-h\t\tDisplays this help information and then
exits.\n");
+ printf("\n");
+}
+
+int start_conversation(void)
+{
+ int result = 1;
+
+ if(verbose || debug) printf("Starting conversation with
%s:%d.\n",hostname,hostport);
+
+ if(debug) printf("Creating the socket.\n");
+ socketfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if(socketfd >= 0)
+ {
+ fprintf(stdout,"Created socket: socketfd=%d.\n", socketfd);
+
+ struct hostent* server = gethostbyname(hostname);
+
+ if(server)
+ {
+ if(debug) printf("Server reference created: server=%x\n",
(unsigned int )server);
+ struct sockaddr_in address;
+
+ bzero((char* ) &address, sizeof(address));
+ address.sin_family = AF_INET;
+ bcopy((char* )server->h_addr, (char*
)&address.sin_addr.s_addr, server->h_length);
+ address.sin_port = hostport;
+
+ int connected = connect(socketfd, &address, sizeof(address));
+
+ if(debug) printf("connected=%d\n", connected);
+
+ if(connected >= 0)
+ {
+ if(debug || verbose) printf("Connected.\n");
+
+ char buffer[128];
+
+ get_text(buffer);
+
+ if(strcmp(buffer,"HELLO?"))
+ {
+ if(send_text("HELLO!\n")) result = 0;
+ }
+ }
+ else
+ {
+ perror("ERROR");
+ }
+ }
+ else
+ {
+ fprintf(stdout,"Invalid hostname: %s\n", hostname);
+ }
+ }
+ else
+ {
+ fprintf(stdout,"Failed to connect to server: %s:%d\n",
hostname, hostport);
+ }
+
+ if(debug) printf("start_conversation: result=%d\n", result);
+
+ return result;
+}
+
+int send_value(char* label,char* value)
+{
+ char buffer[128];
+
+ bzero(buffer,128);
+
+ sprintf(buffer,"%s=%s\n", label, value);
+
+ int result = 0;
+
+ if(send_text(buffer))
+ {
+ char expected[128];
+
+ bzero(expected,128);
+ bzero(buffer,128);
+
+ get_text(buffer);
+
+ sprintf(expected, "ACK %s", label);
+
+ if(strcmp(expected,buffer))
+ {
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+int send_details(void)
+{
+ int result = 0;
+
+ fprintf(stdout,"Sending node details.\n");
+
+ if((send_value("ARCH", arch)) &&
+ (send_value("UUID", uuid)) &&
+ (send_value("NUMCPUS", numcpus)) &&
+ (send_value("CPUSPEED", cpuspeed)) &&
+ (send_value("MEMSIZE", memsize)))
+ {
+ result = 1;
+ }
+
+ return result;
+}
+
+int end_conversation(void)
+{
+ int result = 0;
+
+ fprintf(stdout,"Ending conversation.\n");
+
+ send_text("ENDINFO");
+
+ close(socketfd);
+
+ return result;
+}
+
+int send_text(char* text)
+{
+ int result = 1;
+
+ if(debug || verbose) printf("\"%s\" -> %s:%d\n",
text, hostname, hostport);
+
+ int sent = write(socketfd,text,strlen(text));
+
+ if(sent >= 0)
+ {
+ if(debug) printf("Sent %d bytes total.\n", sent);
+
+ result = 0;
+ }
+
+ return result;
+}
+
+int get_text(char* response)
+{
+ int received = read(socketfd,response,sizeof(response));
+
+ if(debug) printf("Received \"%s\": size=%d\n",
response, received);
+
+ return received;
+}
diff --git a/ovirt-host-creator/common-post.ks
b/ovirt-host-creator/common-post.ks
index d8acab8..a9e4475 100644
--- a/ovirt-host-creator/common-post.ks
+++ b/ovirt-host-creator/common-post.ks
@@ -12,12 +12,15 @@ cat > /etc/sysconfig/iptables << \EOF
COMMIT
EOF
-echo "Writing ovirt-identify-node script"
-cat > /sbin/ovirt-identify-node << \EOF
+echo "Writing ovirt-awake script"
+cat > /sbin/ovirt-awake << \EOF
#!/bin/bash
#
+# ovirt-awake Notifies the oVirt server that a managed node is
+# starting up.
+#
# 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 +37,239 @@ 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
+# 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
}
-send_key_value() {
- echo "$1=$2" 1>&3
+case "$1" in
+ start)
+ KEYTAB_FILE=$2
+ SERVER=$3
+ PORT=$4
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
+EOF
+chmod +x /sbin/ovirt-awake
+
+echo "Writing ovirt-identify script"
+cat > /sbin/ovirt-identify << \EOF
+#!/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
+
+ 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 "IDENTIFY"
+
+ receive-text
+
+ UUID=`hostname -f`
+ ARCH=`uname -i`
+ NUMCPUS=`getconf _NPROCESSORS_ONLN`
+ CPUSPEED=`grep "cpu MHz" /proc/cpuinfo | uniq | cut
-d':' -f2 | sed -e 's/^[[:space:]]*\(.*\)$/\1/' -e
's/^\(.*\)[[:space:]]*$/\1/'`
+ MEMSIZE=$((`getconf _PHYS_PAGES` * `getconf PAGESIZE` / 1024 /
1024))
- read 0<&3
- test "$REPLY" != "ACK $1" && die "Failed
acknowledge of key $1"
+ send-text "UUID=$UUID"
+ receive-text
+ send-text "ARCH=$ARCH"
+ receive-text
+ send-text "NUMCPUS=$NUMCPUS"
+ receive-text
+ send-text "CPUSPEED=$CPUSPEED"
+ receive-text
+ send-text "MEMSIZE=$MEMSIZE"
+ receive-text
+ send-text "ENDINFO"
+
+ receive-text
+
+ if [ $REPLY == "BYE" ]; then
+ echo "Success!"
+ else
+ echo "Error submitting node information..."
+ 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
}
-############# 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
+case "$1" in
+ start)
+ SERVER=$2
+ PORT=$3
+ PORT=$3
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
-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}"
+exit $RETVAL
EOF
-chmod +x /sbin/ovirt-identify-node
+chmod +x /sbin/ovirt-identify
echo "Writing ovirt-functions script"
# common functions
cat > /etc/init.d/ovirt-functions << \EOF
-# -*-Shell-script-*-
+# 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.
-find_srv() {
- local dnsreply
+# 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
- SRV_HOST=$4; SRV_PORT=$3
+ SERVER=$4; PORT=$3
else
- SRV_HOST=; SRV_PORT+ SERVER=; PORT fi
+ fi
+
+ if [ -z $SERVER ]; then
+ echo "No server found..."
+ exit
+ fi
}
+
+# Establishes a TCP connection to the server.
+#
+connect-to-server () {
+ echo "Connecting to $SERVER:$PORT"...
+
+ exec 3<> /dev/tcp/$SERVER/$PORT
+}
+
+# Disconnects form the server.
+#
+disconnect-from-server () {
+ <&3-
+}
+
+# Sends text to the remote server.
+#
+send-text () {
+ echo "Sending: \"$1\""
+ echo "$1" 1>&3
+}
+
+# Receives text from the remote server.
+#
+receive-text () {
+ read 0<&3
+
+ echo "Received: \"$REPLY\""
+}
+
EOF
echo "Writing ovirt-early init script"
@@ -168,7 +301,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 +352,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 +423,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 +434,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
+ ovirt-identify 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 +547,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
Darryl L. Pierce
2008-Jun-16 20:37 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
---
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.c | 407 ++++++++++++++++++++
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, 1006 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.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..1657a67
--- /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.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.c b/ovirt-daemons/ovirt-identify.c
new file mode 100644
index 0000000..7a7ec05
--- /dev/null
+++ b/ovirt-daemons/ovirt-identify.c
@@ -0,0 +1,407 @@
+/* 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 <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;
+
+char arch[128];
+char uuid[128];
+char memsize[128];
+char numcpus[128];
+char cpuspeed[128];
+char hostname[256];
+int hostport = -1;
+int socketfd;
+
+int main(int argc,char** argv)
+{
+ int result = 1;
+
+ if(!config(argc,argv))
+ {
+ int success = 1;
+
+ if(!testing)
+ {
+ success = 0;
+
+ fprintf(stdout,"Connecting to libvirt.\n");
+ virConnectPtr connection = virConnectOpenReadOnly(NULL);
+
+ if(debug) printf("connection=%ld\n",(long
int)connection);
+
+ if(connection)
+ {
+ virNodeInfo info;
+
+ if(debug) printf("Retrieving node information.\n");
+ if(!virNodeGetInfo(connection,&info))
+ {
+ success = 1;
+
+ gethostname(uuid,128);
+ sprintf(arch, "%s", info.model);
+ sprintf(memsize, "%ld", info.memory);
+ sprintf(numcpus, "%d", info.cpus);
+ sprintf(cpuspeed,"%d", info.mhz);
+
+ if(debug)
+ {
+ printf("Node Info:\n");
+ printf(" UUID: %s\n", uuid);
+ printf(" Arch: %s\n", arch);
+ printf(" Memory: %s\n", memsize);
+ printf(" # CPUs: %s\n", numcpus);
+ printf("CPU Speed: %s\n", cpuspeed);
+ }
+ }
+ else
+ {
+ if(debug) printf("Failed to get node info.\n");
+ }
+ }
+ else
+ {
+ if(debug) printf("Could not connect to libvirt.\n");
+ }
+ }
+ else
+ {
+ strcpy(uuid,"UUID-FOR-TESTING-PURPOSES");
+ strcpy(arch,"x86_64");
+ strcpy(memsize,"2048");
+ strcpy(numcpus,"2");
+ strcpy(cpuspeed,"2048");
+ }
+
+ if(success && !start_conversation() && !send_details()
&& !end_conversation()) result = 0;
+ }
+ 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) printf("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)
+ {
+ printf("ERROR: The server name is required. (-s
[hostname])\n");
+ result = 1;
+ }
+
+ if(hostport <= 0)
+ {
+ printf("ERROR: The server port is required. (-p [port])\n");
+ result = 1;
+ }
+
+ return result;
+}
+
+void usage()
+{
+ printf("\n");
+ printf("Usage: ovirt-identify [OPTION]\n");
+ printf("\n");
+ printf("\t-s [server]\t\tThe remote server's hostname.\n");
+ printf("\t-p [port]\t\tThe remote server's port.\n");
+ printf("\t-d\t\tDisplays debug information during execution.\n");
+ printf("\t-v\t\tDisplays verbose information during
execution.\n");
+ printf("\t-h\t\tDisplays this help information and then
exits.\n");
+ printf("\n");
+}
+
+int start_conversation(void)
+{
+ int result = 1;
+
+ if(verbose || debug) printf("Starting conversation with
%s:%d.\n",hostname,hostport);
+
+ if(!create_connection())
+ {
+ if(debug || verbose) printf("Connected.\n");
+
+ char buffer[128];
+
+ get_text(buffer,128);
+
+ if(!strcmp(buffer,"HELLO?"))
+ {
+ if(debug) printf("Checking for handshake.\n");
+
+ if(!send_text("HELLO!"))
+ {
+ if(debug) printf("Handshake received. Starting
conversation.\n");
+
+ get_text(buffer,128);
+
+ if(!strcmp(buffer,"MODE?"))
+ {
+ if(debug) printf("Shifting to IDENTIFY mode.\n");
+
+ if(!send_text("IDENTIFY")) result = 0;
+ }
+ else
+ {
+ if(debug) printf("Was not asked for a mode.\n");
+ }
+ }
+ }
+ else
+ {
+ if(debug) printf("Did not receive a proper
handshake.\n");
+ }
+ }
+
+ else
+ {
+ if(debug) printf("Did not get a connection.\n");
+ }
+
+ if(debug) printf("start_conversation: result=%d\n", result);
+
+ return result;
+}
+
+int send_value(char* label,char* value)
+{
+ char buffer[128];
+
+ bzero(buffer,128);
+
+ sprintf(buffer,"%s=%s", label, value);
+
+ int result = 1;
+
+ if(!send_text(buffer))
+ {
+ char expected[128];
+
+ bzero(expected,128);
+ bzero(buffer,128);
+
+ get_text(buffer,128);
+
+ sprintf(expected, "ACK %s", label);
+
+ if(debug) printf("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[128];
+
+ get_text(buffer,128);
+
+ 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) printf("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;
+}
+
+int send_text(char* text)
+{
+ int result = 1;
+
+ if(debug || verbose) printf("\"%s\" -> %s:%d\n",
text, hostname, hostport);
+
+ char buffer[strlen(text) + 1];
+
+ sprintf(buffer,"%s\n",text);
+
+ int sent = write(socketfd,buffer,strlen(buffer));
+
+ if(sent >= 0)
+ {
+ if(debug) printf("Sent %d bytes total.\n", sent);
+
+ result = 0;
+ }
+
+ return result;
+}
+
+int get_text(char* response,int maxlength)
+{
+ if(debug) printf("Reading up to %d bytes from socket.\n",
maxlength);
+ int received = read(socketfd,response,maxlength);
+
+ response[received - 1] = 0;
+
+ if(debug) printf("Received \"%s\": size=%d (trimmed ending
carriage return)\n", response, received);
+
+ return received;
+}
+
+int create_connection(void)
+{
+ int result = 1;
+
+ if(debug) printf("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) printf("Searching for host candidates.\n");
+
+ char port[6];
+
+ sprintf(port,"%d", hostport);
+
+ if(!getaddrinfo(hostname, port, &hints, &result))
+ {
+ if(debug) printf("Got address information. Searching for a proper
entry.\n");
+ struct addrinfo* rptr;
+
+ for(rptr = result; rptr != NULL; rptr = rptr->ai_next)
+ {
+ if(debug)
+ {
+ printf("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
+ close(socketfd);
+ }
+
+ if(rptr == NULL)
+ {
+ if(debug) printf("Unable to connect to server %s:%d\n",
hostname, hostport);
+ }
+ else
+ {
+ // success
+ result = 0;
+ }
+
+ freeaddrinfo(result);
+ }
+ else
+ {
+ if(debug) printf("No hosts found. Exiting...\n");
+ }
+
+ 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 d8acab8..914b35b 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
Darryl L. Pierce
2008-Jun-17 15:24 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
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
Darryl L. Pierce
2008-Jun-18 19:00 UTC
[Ovirt-devel] [PATCH] Rewriting the identify-node piece into two managed node units
Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
build-all.sh | 1 +
ovirt-host-creator/Makefile | 2 +-
ovirt-host-creator/common-post.ks | 171 +++-----
ovirt-managed-node/AUTHOR | 1 +
ovirt-managed-node/ChangeLog | 2 +
ovirt-managed-node/Makefile | 76 ++++
ovirt-managed-node/NEWS | 2 +
ovirt-managed-node/README | 2 +
ovirt-managed-node/ovirt-awake | 82 ++++
ovirt-managed-node/ovirt-identify | 46 ++
ovirt-managed-node/ovirt-identify-node.c | 457 ++++++++++++++++++++
ovirt-managed-node/ovirt-managed-node.spec | 45 ++
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 ---------
16 files changed, 1087 insertions(+), 366 deletions(-)
create mode 100644 ovirt-managed-node/AUTHOR
create mode 100644 ovirt-managed-node/ChangeLog
create mode 100644 ovirt-managed-node/Makefile
create mode 100644 ovirt-managed-node/NEWS
create mode 100644 ovirt-managed-node/README
create mode 100644 ovirt-managed-node/ovirt-awake
create mode 100644 ovirt-managed-node/ovirt-identify
create mode 100644 ovirt-managed-node/ovirt-identify-node.c
create mode 100644 ovirt-managed-node/ovirt-managed-node.spec
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/build-all.sh b/build-all.sh
index fcf1563..d775d66 100755
--- a/build-all.sh
+++ b/build-all.sh
@@ -123,6 +123,7 @@ fi
set -e
# build ovirt-wui RPM
+# also build the ovirt-managed-node RPM
if [ $update_wui = 1 ]; then
cd $BASE/wui
rm -rf rpm-build
diff --git a/ovirt-host-creator/Makefile b/ovirt-host-creator/Makefile
index b7d98ec..12a8b77 100644
--- a/ovirt-host-creator/Makefile
+++ b/ovirt-host-creator/Makefile
@@ -39,7 +39,7 @@ 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
+build: ovirt-$(ARCH).ks common-install.ks common-pkgs.ks common-post.ks
repos.ks
-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..7e27da0 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 $SRV_HOST ]; then
+ 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
+ fi
+
+ if [ -z $SRV_HOST ]; 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 $SRV_HOST:$SRV_PORT"...
- read 0<&3
- test "$REPLY" != "ACK $1" && die "Failed
acknowledge of key $1"
+ exec 3<> /dev/tcp/$SRV_HOST/$SRV_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,16 +163,16 @@ 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
@@ -283,7 +227,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 +238,14 @@ start() {
IPA_HOST=$SRV_HOST
IPA_PORT=$SRV_PORT
- find_srv identify tcp
+ # Notify the server we're awake and retrieve a keytab file
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"
+ ovirt-awake start $krb5_tab
fi
+ /sbin/ovirt-identify 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 +356,8 @@ LoadPlugin disk
</Plugin>
<Plugin interface>
- Interface "eth0"
- IgnoreSelected false
+ Interface "eth0"
+ IgnoreSelected false
</Plugin>
EOF
diff --git a/ovirt-managed-node/AUTHOR b/ovirt-managed-node/AUTHOR
new file mode 100644
index 0000000..d37a107
--- /dev/null
+++ b/ovirt-managed-node/AUTHOR
@@ -0,0 +1 @@
+Darryl L. Pierce <dpierce at redhat.com>
diff --git a/ovirt-managed-node/ChangeLog b/ovirt-managed-node/ChangeLog
new file mode 100644
index 0000000..61dc8cc
--- /dev/null
+++ b/ovirt-managed-node/ChangeLog
@@ -0,0 +1,2 @@
+* Tue 17 Jun 2008 Darryl L. Pierce <dpierce at redhat.com> - 0.0.1-1
+- Created the initial RPM structure.
diff --git a/ovirt-managed-node/Makefile b/ovirt-managed-node/Makefile
new file mode 100644
index 0000000..564be1d
--- /dev/null
+++ b/ovirt-managed-node/Makefile
@@ -0,0 +1,76 @@
+# 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-managed-node.spec
+NAME=ovirt-managed-node
+VERSION=0.1
+NV=$(NAME)-$(VERSION)
+RPM_FLAGS=\
+ --define "_topdir %(pwd)/rpm-build" \
+ --define "_builddir %{_topdir}" \
+ --define "_rpmdir %{_topdir}" \
+ --define "_srcrpmdir %{_topdir}" \
+ --define '_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm'
\
+ --define "_specdir %{_topdir}" \
+ --define "_sourcedir %{_topdir}"
+SOURCES=\
+ AUTHOR \
+ ChangeLog \
+ Makefile \
+ NEWS \
+ ovirt-awake \
+ ovirt-identify \
+ ovirt-identify-node.c \
+ ovirt-managed-node.spec \
+ README
+
+
+ALL: $(TARGET)
+
+.c.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -rf $(OBJECTS) $(TARGET) $(NV) rpm-build
+
+bumpgit:
+ -echo "$(VERSION) $(GITRELEASE)" > version
+
+bumprelease:
+ -echo "$(VERSION) $(NEWRELEASE)" > version
+
+setversion:
+ -echo "$(VERSION) 0" > version
+
+$(TARGET): $(OBJECTS)
+ $(CC) -o $@ $(OBJECTS) $(LFLAGS)
+
+tar: clean $(TARGET)
+ mkdir -p $(NV)
+ cp -a $(SOURCES) $(NV)
+ mkdir -p rpm-build
+ tar zcvf rpm-build/$(NV).tar $(NV)
+ rm -rf $(NV)
+
+rpms: tar
+ rpmbuild $(RPM_FLAGS) -ba $(SPECFILE)
diff --git a/ovirt-managed-node/NEWS b/ovirt-managed-node/NEWS
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/ovirt-managed-node/NEWS
@@ -0,0 +1,2 @@
+
+
diff --git a/ovirt-managed-node/README b/ovirt-managed-node/README
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/ovirt-managed-node/README
@@ -0,0 +1,2 @@
+
+
diff --git a/ovirt-managed-node/ovirt-awake b/ovirt-managed-node/ovirt-awake
new file mode 100644
index 0000000..f7f643b
--- /dev/null
+++ b/ovirt-managed-node/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
+ SRV_HOST=$3
+ SRV_PORT=$4
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
diff --git a/ovirt-managed-node/ovirt-identify
b/ovirt-managed-node/ovirt-identify
new file mode 100644
index 0000000..53f21b0
--- /dev/null
+++ b/ovirt-managed-node/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 $SRV_HOST -p $SRV_PORT
+}
+
+case "$1" in
+ start)
+ SRV_HOST=$2
+ SRV_PORT=$3
+ start
+ RETVAL=$?
+ ;;
+
+ *)
+ echo "Usage: $0 start"
+ RETVAL=2
+ ;;
+esac
+
+exit $RETVAL
diff --git a/ovirt-managed-node/ovirt-identify-node.c
b/ovirt-managed-node/ovirt-identify-node.c
new file mode 100644
index 0000000..3689eca
--- /dev/null
+++ b/ovirt-managed-node/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-managed-node/ovirt-managed-node.spec
b/ovirt-managed-node/ovirt-managed-node.spec
new file mode 100644
index 0000000..7f33344
--- /dev/null
+++ b/ovirt-managed-node/ovirt-managed-node.spec
@@ -0,0 +1,45 @@
+Summary: The managed node demons for oVirt.
+Name: ovirt-managed-node
+Version: 0.1
+Release: 1%{?dist}
+License: Fedora
+Group: Applications/System
+Source0: http://www.ovirt.org/sources/%{name}-%{version}.tar
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+URL: http://www.ovirt.org/
+BuildRequires: libvirt-devel
+Requires: libvirt
+ExclusiveArch: %{ix86} x86_64 ia64
+
+
+%description
+Provides a series of daemons and support utilities to allow an
+oVirt managed node to interact with the oVirt server.
+
+
+%prep
+%setup
+
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT
+
+
+%build
+make
+
+mkdir -p $RPM_BUILD_ROOT/sbin
+cp ovirt-awake $RPM_BUILD_ROOT/sbin
+cp ovirt-identify $RPM_BUILD_ROOT/sbin
+cp ovirt-identify-node $RPM_BUILD_ROOT/sbin
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(755,root,root)
+%doc README NEWS AUTHOR ChangeLog
+/sbin/ovirt-awake
+/sbin/ovirt-identify
+/sbin/ovirt-identify-node
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