[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Ovirt-devel] [PATCH] Enables the generation of a configuration file for a managed node.



The configuration is generated from the contents of the nics table. The
managed node then downloads that configuration after completing the
identification and applies those changes.

Signed-off-by: Darryl L. Pierce <dpierce redhat com>
---
 ovirt-managed-node/src/gather.c                    |    2 +
 ovirt-managed-node/src/ovirt-identify-node.h       |    1 +
 ovirt-managed-node/src/protocol.c                  |    3 +-
 wui/src/app/controllers/application.rb             |    2 +-
 wui/src/app/controllers/nic_controller.rb          |   13 +-
 wui/src/config/environment.rb                      |    2 +
 wui/src/db/migrate/015_add_iface_name_to_nics.rb   |    9 +
 wui/src/host-browser/host-browser.rb               |  583 ++++++++++----------
 wui/src/host-browser/test-host-browser-awake.rb    |   94 ----
 wui/src/host-browser/test-host-browser-identify.rb |  283 ----------
 wui/src/lib/managed_node_configuration.rb          |   49 ++
 wui/src/test/fixtures/nics.yml                     |    3 +
 wui/src/test/unit/host_browser_awaken_test.rb      |   96 ++++
 wui/src/test/unit/host_browser_identify_test.rb    |  304 ++++++++++
 .../test/unit/managed_node_configuration_test.rb   |   87 +++
 15 files changed, 864 insertions(+), 667 deletions(-)
 create mode 100644 wui/src/db/migrate/015_add_iface_name_to_nics.rb
 delete mode 100755 wui/src/host-browser/test-host-browser-awake.rb
 delete mode 100755 wui/src/host-browser/test-host-browser-identify.rb
 create mode 100644 wui/src/lib/managed_node_configuration.rb
 create mode 100755 wui/src/test/unit/host_browser_awaken_test.rb
 create mode 100755 wui/src/test/unit/host_browser_identify_test.rb
 create mode 100644 wui/src/test/unit/managed_node_configuration_test.rb

diff --git a/ovirt-managed-node/src/gather.c b/ovirt-managed-node/src/gather.c
index 39be6fd..7fa0992 100644
--- a/ovirt-managed-node/src/gather.c
+++ b/ovirt-managed-node/src/gather.c
@@ -205,6 +205,8 @@ get_nic_data(char *nic, nic_info_ptr nic_info)
     interface =
         libhal_device_get_property_string(hal_ctx, nic, "net.interface",
                                           &dbus_error);
+    snprintf(nic_info->interface_name, BUFFER_LENGTH, "%s", interface);
+    
     bzero(&ifr, sizeof(struct ifreq));
 
     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
diff --git a/ovirt-managed-node/src/ovirt-identify-node.h b/ovirt-managed-node/src/ovirt-identify-node.h
index c595891..b2814fa 100644
--- a/ovirt-managed-node/src/ovirt-identify-node.h
+++ b/ovirt-managed-node/src/ovirt-identify-node.h
@@ -67,6 +67,7 @@ typedef struct _nic_info {
     char mac_address[BUFFER_LENGTH];
     char bandwidth[BUFFER_LENGTH];
     char ip_address[BUFFER_LENGTH];
+    char interface_name[BUFFER_LENGTH];
     struct _nic_info* next;
 } t_nic_info;
 
diff --git a/ovirt-managed-node/src/protocol.c b/ovirt-managed-node/src/protocol.c
index 131bb38..d5c5fac 100644
--- a/ovirt-managed-node/src/protocol.c
+++ b/ovirt-managed-node/src/protocol.c
@@ -181,7 +181,8 @@ send_nic_details(void)
 
         if (!(get_text("NICINFO?")) &&
             (!send_value("MAC", current->mac_address)) &&
-            (!send_value("BANDWIDTH", current->bandwidth))) {
+            (!send_value("BANDWIDTH", current->bandwidth)) &&
+            (!send_value("IFACE_NAME", current->interface_name))) {
             send_text("ENDNIC");
             result = get_text("ACK NIC");
         }
diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb
index d653171..b27ddbe 100644
--- a/wui/src/app/controllers/application.rb
+++ b/wui/src/app/controllers/application.rb
@@ -35,7 +35,7 @@ class ApplicationController < ActionController::Base
   before_filter :is_logged_in
 
   def is_logged_in
-    redirect_to (:controller => "login", :action => "login") unless get_login_user
+    redirect_to(:controller => "login", :action => "login") unless get_login_user
   end
 
   def get_login_user
diff --git a/wui/src/app/controllers/nic_controller.rb b/wui/src/app/controllers/nic_controller.rb
index 85d4315..fef7c5b 100644
--- a/wui/src/app/controllers/nic_controller.rb
+++ b/wui/src/app/controllers/nic_controller.rb
@@ -18,9 +18,10 @@
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
 class NicController < ApplicationController
+  after_filter :generate_configuration, :only => [:create, :edit, :update, :destroy]
   # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
   verify :method => :post, :only => [ :destroy, :create, :update ],
-         :redirect_to => { :controller => 'dashboard' }
+    :redirect_to => { :controller => 'dashboard' }
 
   def show
     set_perms(@perm_obj)
@@ -44,8 +45,18 @@ class NicController < ApplicationController
 
   def destroy
   end
+  
+  def generate_configuration
+    host = Host.find_by_id(params[:host_id])
+
+    File.open("#{MANAGED_NODE_CONFIGURATION_DIR}/#{host.hostname}", "w") do |file|    
+      # write the nic configuration
+      file.puts ManagedNodeConfiguration.generate(host)
+    end
+  end
 
   private
+  
   #filter methods
   def pre_new
     flash[:notice] = 'Network Interfaces may not be edited via the web UI'
diff --git a/wui/src/config/environment.rb b/wui/src/config/environment.rb
index ff6f6e8..57fd461 100644
--- a/wui/src/config/environment.rb
+++ b/wui/src/config/environment.rb
@@ -80,3 +80,5 @@ end
 require 'gettext/rails'                                                                                                                                                     
 gem 'cobbler'
 require 'cobbler'
+
+MANAGED_NODE_CONFIGURATION_DIR = '/var/www/html/ovirt-cfgdb'
\ No newline at end of file
diff --git a/wui/src/db/migrate/015_add_iface_name_to_nics.rb b/wui/src/db/migrate/015_add_iface_name_to_nics.rb
new file mode 100644
index 0000000..f1fb28d
--- /dev/null
+++ b/wui/src/db/migrate/015_add_iface_name_to_nics.rb
@@ -0,0 +1,9 @@
+class AddIfaceNameToNics < ActiveRecord::Migration
+  def self.up
+    add_column :nics, :iface_name, :string, :limit => 10
+  end
+
+  def self.down
+    remove_column :nics, :iface_name
+  end
+end
diff --git a/wui/src/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb
index 881b2ae..d3098ce 100755
--- a/wui/src/host-browser/host-browser.rb
+++ b/wui/src/host-browser/host-browser.rb
@@ -39,361 +39,370 @@ $logfile = '/var/log/ovirt-wui/host-browser.log'
 # about the node and then updates the list of active nodes for the WUI.
 #
 class HostBrowser
-    attr_accessor :logfile
-    attr_accessor :keytab_dir
-    attr_accessor :keytab_filename
-
-    def initialize(session)
-        @session = session
-        @log_prefix = "[#{session.peeraddr[3]}] "
-        @keytab_dir = '/usr/share/ipa/html/'
-    end
-
-    # Ensures the conversation starts properly.
-    #
-    def 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)
+  attr_accessor :logfile
+  attr_accessor :keytab_dir
+  attr_accessor :keytab_filename
+
+  def initialize(connection)
+    @connection = connection
+    @log_prefix = "[#{connection.peeraddr[3]}] "
+    @keytab_dir = '/usr/share/ipa/html/'
+  end
+
+  # Ensures the conversation starts properly.
+  #
+  def begin_conversation
+    puts "#{ log_prefix} Begin conversation" unless defined?(TESTING)
+    @connection.write("HELLO?\n")
+
+    response = @connection.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)
+    @connection.write("MODE?\n")
+    response = @connection.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" unless defined?(TESTING)
+    result = Hash.new
+    result['HOSTNAME'] = @connection.peeraddr[2]
+    result['IPADDR']   = @connection.peeraddr[3]
+
+    @connection.write("INFO?\n")
+
+    loop do
+      info = @connection.readline.chomp
+
+      puts "Received info='#{info}'"
+
+      break if info == "ENDINFO"
+
+      case info
+      when "CPU"
+        cpu = get_cpu_info
+        cpu_info = result['CPUINFO']
+
+        if(cpu_info == nil)
+          cpu_info = Array.new
+          result['CPUINFO'] = cpu_info
+        end
 
-        response
-    end
+        cpu_info << cpu
+                
+      when "NIC"
+        nic = get_nic_info
+        nic_info = result['NICINFO']
 
-    # Requests node information from the remote system.
-    #
-    def get_remote_info
-        puts "#{ log_prefix} Begin remote info collection" unless defined?(TESTING)
-        result = Hash.new
-        result['HOSTNAME'] = @session.peeraddr[2]
-        result['IPADDR']   = @session.peeraddr[3]
+        if(nic_info == nil)
+          nic_info = Array.new
+          result['NICINFO'] = nic_info
+        end
 
-        @session.write("INFO?\n")
+        nic_info << nic
+                
+      else
+        raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
 
-        loop do
-            info = @session.readline.chomp
+        key, value = info.split("=")
 
-            puts "Received info='#{info}'"
+        puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
+        result[key] = value
 
-            break if info == "ENDINFO"
+        @connection.write("ACK #{key}\n")
+      end
+    end
 
-            case info
-            when "CPU"
-                cpu = get_cpu_info
-                cpu_info = result['CPUINFO']
+    return result
+  end
 
-                if(cpu_info == nil)
-                    cpu_info = Array.new
-                    result['CPUINFO'] = cpu_info
-                end
+  # Extracts CPU details from the managed node.
+  #
+  def get_cpu_info
+    puts "Begin receiving CPU details"
 
-                cpu_info << cpu
-            when "NIC"
-                nic = get_nic_info
-                nic_info = result['NICINFO']
+    result = Hash.new
 
-                if(nic_info == nil)
-                    nic_info = Array.new
-                    result['NICINFO'] = nic_info
-                end
+    @connection.write("CPUINFO?\n")
 
-                nic_info << nic
-            else
+    loop do
+      info = @connection.readline.chomp
 
-                raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
+      break if info == "ENDCPU"
 
-                key, value = info.split("=")
+      raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
 
-                puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
-                result[key] = value
+      key, value = info.split("=")
 
-                @session.write("ACK #{key}\n")
-            end
-        end
+      puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
+      result[key] = value
 
-        return result
+      @connection.write("ACK #{key}\n")
     end
 
-    # Extracts CPU details from the managed node.
-    #
-    def get_cpu_info
-        puts "Begin receiving CPU details"
+    @connection.write("ACK CPU\n");
 
-        result = Hash.new
+    return result
+  end
 
-        @session.write("CPUINFO?\n")
+  # Extracts NIC details from the managed node.
+  #
+  def get_nic_info
+    puts "Begin receiving NIC details"
 
-        loop do
-            info = @session.readline.chomp
+    result = Hash.new
 
-            break if info == "ENDCPU"
+    @connection.write("NICINFO?\n")
 
-            raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
+    loop do
+      info = @connection.readline.chomp
 
-            key, value = info.split("=")
+      break if info == "ENDNIC"
 
-            puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
-            result[key] = value
+      raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
 
-            @session.write("ACK #{key}\n")
-        end
+      key, value = info.split("=")
 
-        @session.write("ACK CPU\n");
+      puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
+      result[key] = value
 
-        return result
+      @connection.write("ACK #{key}\n")
     end
 
-    # Extracts NIC details from the managed node.
-    #
-    def get_nic_info
-        puts "Begin receiving NIC details"
-
-        result = Hash.new
-
-        @session.write("NICINFO?\n")
+    @connection.write("ACK NIC\n");
+
+    return result
+  end
+
+  # Writes the supplied host information to the database.
+  #
+  def write_host_info(host_info)
+    ensure_present(host_info,'HOSTNAME')
+    ensure_present(host_info,'ARCH')
+    ensure_present(host_info,'MEMSIZE')
+    ensure_present(host_info,'CPUINFO')
+    ensure_present(host_info,'NICINFO')
+
+    cpu_info = host_info['CPUINFO']
+    nic_info = host_info['NICINFO']
+
+    cpu_info.each do |cpu|
+      ensure_present(cpu,'CPUNUM')
+      ensure_present(cpu,'CORENUM')
+      ensure_present(cpu,'NUMCORES')
+      ensure_present(cpu,'VENDOR')
+      ensure_present(cpu,'MODEL')
+      ensure_present(cpu,'FAMILY')
+      ensure_present(cpu,'CPUIDLVL')
+      ensure_present(cpu,'SPEED')
+      ensure_present(cpu,'CACHE')
+      ensure_present(cpu,'FLAGS')
+    end
+        
+    nic_info.each do |nic|
+      ensure_present(nic, 'MAC')
+      ensure_present(nic, 'BANDWIDTH')
+      ensure_present(nic, 'IFACE_NAME')
+    end
 
-        loop do
-            info = @session.readline.chomp
+    puts "Searching for existing host record..." unless defined?(TESTING)
+    host = Host.find(:first, :conditions => ["hostname = ?", host_info['HOSTNAME']])
+
+    if host == nil
+      begin
+        puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING)
+
+        host = Host.create(
+          "uuid"            => host_info['UUID'],
+          "hostname"        => host_info['HOSTNAME'],
+          "hypervisor_type" => host_info['HYPERVISOR_TYPE'],
+          "arch"            => host_info['ARCH'],
+          "memory"          => host_info['MEMSIZE'],
+          "is_disabled"     => 0,
+          "hardware_pool"   => HardwarePool.get_default_pool,
+          # Let host-status mark it available when it
+          # successfully connects to it via libvirt.
+          "state"           => Host::STATE_UNAVAILABLE)
+      rescue Exception => error
+        puts "Error while creating record: #{error.message}" unless defined?(TESTING)
+      end
+    else
+      host.uuid         = host_info['UUID']
+      host.hostname     = host_info['HOSTNAME']
+      host.arch         = host_info['ARCH']
+      host.memory       = host_info['MEMSIZE']
+    end
 
-            break if info == "ENDNIC"
+    # delete an existing CPUs and create new ones based on the data
+    puts "Deleting any existing CPUs"
+    Cpu.delete_all(['host_id = ?', host.id])
+
+    puts "Saving new CPU records"
+    cpu_info.collect do |cpu|
+      detail = Cpu.new(
+        "cpu_number"      => cpu['CPUNUM'],
+        "core_number"     => cpu['CORENUM]'],
+        "number_of_cores" => cpu['NUMCORES'],
+        "vendor"          => cpu['VENDOR'],
+        "model"           => cpu['MODEL'],
+        "family"          => cpu['FAMILY'],
+        "cpuid_level"     => cpu['CPUIDLVL'],
+        "speed"           => cpu['SPEED'],
+        "cache"           => cpu['CACHE'],
+        "flags"           => cpu['FLAGS'])
+
+      host.cpus << detail
+    end
 
-            raise Exception.new("ERRINFO! Excepted key=value : #{info}\n") unless info =~ /[\w]+[\s]*=[\w]/
+    # Update the NIC details for this host:
+    # -if the NIC exists, then update the IP address
+    # -if the NIC does not exist, create it
+    # -any nic not in this list is deleted
 
-            key, value = info.split("=")
+    puts "Updating NIC records for the node"
+    nics = Array.new
 
-            puts "#{ log_prefix} ::Received - #{key}:#{value}" unless defined?(TESTING)
-            result[key] = value
+    host.nics.collect do |nic|
+      found = false
 
-            @session.write("ACK #{key}\n")
+      nic_info.collect do |detail|
+        # if we have a match, then update the database and remove
+        # the received data to avoid creating a dupe later
+        if detail['MAC'] == nic.mac
+          nic_info.delete(detail)
+          found = true
         end
+      end
 
-        @session.write("ACK NIC\n");
-
-        return result
+      # if the record wasn't found, then remove it from the database
+      unless found
+        host.nics.delete(nic)
+        nic.destroy
+      end
     end
 
-    # Writes the supplied host information to the database.
-    #
-    def write_host_info(host_info)
-        ensure_present(host_info,'HOSTNAME')
-        ensure_present(host_info,'ARCH')
-        ensure_present(host_info,'MEMSIZE')
-        ensure_present(host_info,'CPUINFO')
-        ensure_present(host_info,'NICINFO')
-
-        cpu_info = host_info['CPUINFO']
-        nic_info = host_info['NICINFO']
-
-        cpu_info.each do |cpu|
-            ensure_present(cpu,'CPUNUM')
-            ensure_present(cpu,'CORENUM')
-            ensure_present(cpu,'NUMCORES')
-            ensure_present(cpu,'VENDOR')
-            ensure_present(cpu,'MODEL')
-            ensure_present(cpu,'FAMILY')
-            ensure_present(cpu,'CPUIDLVL')
-            ensure_present(cpu,'SPEED')
-            ensure_present(cpu,'CACHE')
-            ensure_present(cpu,'FLAGS')
-        end
+    # iterate over any nics left and create new records for them.
 
-        puts "Searching for existing host record..." unless defined?(TESTING)
-        host = Host.find(:first, :conditions => ["hostname = ?", host_info['HOSTNAME']])
-
-        if host == nil
-            begin
-                puts "Creating a new record for #{host_info['HOSTNAME']}..." unless defined?(TESTING)
-
-                host = Host.create(
-                    "uuid"            => host_info['UUID'],
-                    "hostname"        => host_info['HOSTNAME'],
-                    "hypervisor_type" => host_info['HYPERVISOR_TYPE'],
-                    "arch"            => host_info['ARCH'],
-                    "memory"          => host_info['MEMSIZE'],
-                    "is_disabled"     => 0,
-                    "hardware_pool"   => HardwarePool.get_default_pool,
-                    # Let host-status mark it available when it
-                    # successfully connects to it via libvirt.
-                    "state"           => Host::STATE_UNAVAILABLE)
-            rescue Exception => error
-                puts "Error while creating record: #{error.message}" unless defined?(TESTING)
-            end
-        else
-            host.uuid         = host_info['UUID']
-            host.hostname     = host_info['HOSTNAME']
-            host.arch         = host_info['ARCH']
-            host.memory       = host_info['MEMSIZE']
-        end
+    nic_info.collect do |nic|
+      puts "Creating a new nic..."
+      detail = Nic.new(
+        'mac'        => nic['MAC'],
+        'bandwidth'  => nic['BANDWIDTH'],
+        'iface_name' => nic['IFACE_NAME'],
+        'usage_type' => 1)
 
-        # delete an existing CPUs and create new ones based on the data
-        puts "Deleting any existing CPUs"
-        Cpu.delete_all(['host_id = ?', host.id])
-
-        puts "Saving new CPU records"
-        cpu_info.collect do |cpu|
-            detail = Cpu.new(
-                "cpu_number"      => cpu['CPUNUM'],
-                "core_number"     => cpu['CORENUM]'],
-                "number_of_cores" => cpu['NUMCORES'],
-                "vendor"          => cpu['VENDOR'],
-                "model"           => cpu['MODEL'],
-                "family"          => cpu['FAMILY'],
-                "cpuid_level"     => cpu['CPUIDLVL'],
-                "speed"           => cpu['SPEED'],
-                "cache"           => cpu['CACHE'],
-                "flags"           => cpu['FLAGS'])
-
-            host.cpus << detail
-         end
-
-        # Update the NIC details for this host:
-        # -if the NIC exists, then update the IP address
-        # -if the NIC does not exist, create it
-        # -any nic not in this list is deleted
-
-        puts "Updating NIC records for the node"
-        nics = Array.new
-
-        host.nics.collect do |nic|
-            found = false
-
-            nic_info.collect do |detail|
-                # if we have a match, then update the database and remove
-                # the received data to avoid creating a dupe later
-                if detail['MAC'] == nic.mac
-                    nic_info.delete(detail)
-                end
-            end
-
-            # if the record wasn't found, then remove it from the database
-            unless found
-                host.nics.delete(nic)
-                nic.destroy
-            end
-        end
-
-        # iterate over any nics left and create new records for them.
-
-        nic_info.collect do |nic|
-            puts "Creating a new nic..."
-            detail = Nic.new(
-                'mac'        => nic['MAC'],
-                'bandwidth'  => nic['BANDWIDTH'],
-                'usage_type' => 1)
+      host.nics << detail
+    end
 
-            host.nics << detail
-        end
+    host.save!
 
-        host.save!
+    return host
+  end
 
-        return host
-    end
+  # Creates a keytab if one is needed, returning the filename.
+  #
+  def create_keytab(hostname, ipaddress, krb5_arg = nil)
+    krb5 = krb5_arg || Krb5.new
 
-    # Creates a keytab if one is needed, returning the filename.
-    #
-    def create_keytab(hostname, ipaddress, krb5_arg = nil)
-        krb5 = krb5_arg || Krb5.new
+    default_realm = krb5.get_default_realm
+    libvirt_princ = 'libvirt/' + hostname + '@' + default_realm
+    outfile = ipaddress + '-libvirt.tab'
+    @keytab_filename = @keytab_dir + outfile
 
-        default_realm = krb5.get_default_realm
-        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}" unless defined?(TESTING)
+      kadmin_local('addprinc -randkey ' + libvirt_princ)
+      kadmin_local('ktadd -k ' + @keytab_filename + ' ' + libvirt_princ)
 
-        # 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}" unless defined?(TESTING)
-            kadmin_local('addprinc -randkey ' + libvirt_princ)
-            kadmin_local('ktadd -k ' + @keytab_filename + ' ' + libvirt_princ)
+      File.chmod(0644,@keytab_filename)
+    end
 
-            File.chmod(0644,@keytab_filename)
-        end
+    hostname = `hostname -f`.chomp
 
-        hostname = `hostname -f`.chomp
+    @connection.write("KTAB http://#{hostname}/ipa/config/#{outfile}\n";)
 
-        @session.write("KTAB http://#{hostname}/ipa/config/#{outfile}\n";)
+    response = @connection.readline.chomp
 
-        response = @session.readline.chomp
+    raise Exception.new("ERRINFO! No keytab acknowledgement") unless response == "ACK"
+  end
 
-        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)
 
-    # Ends the conversation, notifying the user of the key version number.
-    #
-    def end_conversation
-        puts "#{ log_prefix} Ending conversation" unless defined?(TESTING)
+    @connection.write("BYE\n");
+  end
 
-        @session.write("BYE\n");
-    end
+  private
 
-    private
+  # Private method to ensure that a required field is present.
+  #
+  def ensure_present(info,key)
+    raise Exception.new("ERROR! Missing '#{key}'...") if info[key] == nil
+  end
 
-    # Private method to ensure that a required field is present.
-    #
-    def ensure_present(info,key)
-        raise Exception.new("ERROR! Missing '#{key}'...") if info[key] == nil
-    end
-
-    # Executes an external program to support the keytab function.
-    #
-    def kadmin_local(command)
-        system("/usr/kerberos/sbin/kadmin.local -q '" + command + "'")
-    end
+  # Executes an external program to support the keytab function.
+  #
+  def kadmin_local(command)
+    system("/usr/kerberos/sbin/kadmin.local -q '" + command + "'")
+  end
 end
 
 def entry_point(server)
-    while(session = server.accept)
-        child = fork do
-            remote = session.peeraddr[2]
-
-            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
+  while(session = server.accept)
+    child = fork do
+      remote = session.peeraddr[2]
 
-            begin
-                browser = HostBrowser.new(session)
+      puts "Connected to #{remote}" unless defined?(TESTING)
 
-                browser.begin_conversation
-                case browser.get_mode
-                    when "AWAKEN": browser.create_keytab(remote,session.peeraddr[3])
-                    when "IDENTIFY": browser.write_host_info(browser.get_remote_info)
-                end
+      # This is needed because we just forked a new process
+      # which now needs its own connection to the database.
+      database_connect
 
-                browser.end_conversation
-            rescue Exception => error
-                session.write("ERROR #{error.message}\n")
-                puts "ERROR #{error.message}" unless defined?(TESTING)
-            end
+      begin
+        browser = HostBrowser.new(session)
 
-            puts "Disconnected from #{remote}" unless defined?(TESTING)
+        browser.begin_conversation
+        case browser.get_mode
+        when "AWAKEN": browser.create_keytab(remote,session.peeraddr[3])
+        when "IDENTIFY": browser.write_host_info(browser.get_remote_info)
         end
 
-        Process.detach(child)
+        browser.end_conversation
+      rescue Exception => error
+        session.write("ERROR #{error.message}\n")
+        puts "ERROR #{error.message}" unless defined?(TESTING)
+      end
+
+      puts "Disconnected from #{remote}" unless defined?(TESTING)
     end
+
+    Process.detach(child)
+  end
 end
 
 unless defined?(TESTING)
-    # The main entry point.
-    #
-    unless ARGV[0] == "-n"
-        daemonize
-        # redirect output to the log
-        STDOUT.reopen $logfile, 'a'
-        STDERR.reopen STDOUT
-    end
-
-    server = TCPServer.new("",12120)
-    entry_point(server)
+  # The main entry point.
+  #
+  unless ARGV[0] == "-n"
+    daemonize
+    # redirect output to the log
+    STDOUT.reopen $logfile, 'a'
+    STDERR.reopen STDOUT
+  end
+
+  server = TCPServer.new("",12120)
+  entry_point(server)
 end
diff --git a/wui/src/host-browser/test-host-browser-awake.rb b/wui/src/host-browser/test-host-browser-awake.rb
deleted file mode 100755
index 02e9146..0000000
--- a/wui/src/host-browser/test-host-browser-awake.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/ruby -Wall
-#
-# Copyright (C) 2008 Red Hat, Inc.
-# Written by Darryl L. Pierce <dpierce 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}/ipa/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',@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
deleted file mode 100755
index 7e672ce..0000000
--- a/wui/src/host-browser/test-host-browser-identify.rb
+++ /dev/null
@@ -1,283 +0,0 @@
-#!/usr/bin/ruby -Wall
-#
-# Copyright (C) 2008 Red Hat, Inc.
-# Written by Darryl L. Pierce <dpierce 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'] = 'prod.corp.com'
-        @host_info['ARCH']     = 'x86_64'
-        @host_info['MEMSIZE']  = '16384'
-        @host_info['DISABLED'] = '0'
-
-        @host_info['NUMCPUS']  = '2'
-
-        @host_info['CPUINFO'] = Array.new
-        @host_info['CPUINFO'][0] = {}
-        @host_info['CPUINFO'][0]['CPUNUM']   = '0'
-        @host_info['CPUINFO'][0]['CORENUM']  = '0'
-        @host_info['CPUINFO'][0]['NUMCORES'] = '2'
-        @host_info['CPUINFO'][0]['VENDOR']   = 'GenuineIntel'
-        @host_info['CPUINFO'][0]['MODEL']    = '15'
-        @host_info['CPUINFO'][0]['FAMILY']   = '6'
-        @host_info['CPUINFO'][0]['CPUIDLVL'] = '10'
-        @host_info['CPUINFO'][0]['SPEED']    = '3'
-        @host_info['CPUINFO'][0]['CACHE']    = '4096 kb'
-        @host_info['CPUINFO'][0]['FLAGS']    = 'fpu vme de pse tsc msr pae \
-            mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
-            fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
-            bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
-
-        @host_info['CPUINFO'][1] = {}
-        @host_info['CPUINFO'][1]['CPUNUM']   = '1'
-        @host_info['CPUINFO'][1]['CORENUM']  = '1'
-        @host_info['CPUINFO'][1]['NUMCORES'] = '2'
-        @host_info['CPUINFO'][1]['VENDOR']   = 'GenuineIntel'
-        @host_info['CPUINFO'][1]['MODEL']    = '15'
-        @host_info['CPUINFO'][1]['FAMILY']   = '6'
-        @host_info['CPUINFO'][1]['CPUIDLVL'] = '10'
-        @host_info['CPUINFO'][1]['SPEED']    = '3'
-        @host_info['CPUINFO'][1]['CACHE']    = '4096 kb'
-        @host_info['CPUINFO'][1]['FLAGS']    = 'fpu vme de pse tsc msr pae \
-            mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
-            fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
-            bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
-
-        @host_info['NICINFO'] = Array.new
-        @host_info['NICINFO'][0] = {}
-        @host_info['NICINFO'][0]['MAC']       = '00:11:22:33:44:55'
-        @host_info['NICINFO'][0]['BANDWIDTH'] = '100'
-
-        @host_info['NICINFO'][1] = {}
-        @host_info['NICINFO'][1]['MAC']       = '00:77:11:77:19:65'
-        @host_info['NICINFO'][1]['BANDWIDTH'] = '100'
-    end
-
-    # Ensures that the server is satisfied if the remote system is
-    # 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 four keys"
-        assert info.include?("IPADDR")
-        assert info.include?("HOSTNAME")
-        assert info.include?("key1")
-        assert info.include?("key2")
-    end
-
-    # Ensures that the server is fine when no UUID is present.
-    #
-    def test_write_host_info_with_missing_uuid
-        @host_info['UUID'] = nil
-
-        assert_nothing_raised { @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 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 no cpu info was available, the server raises an
-    # exception.
-    #
-    def test_write_host_info_with_missing_cpuinfo
-        @host_info['CPUINFO'] = nil
-
-        assert_raise(Exception) { @browser.write_host_info(@host_info) }
-    end
-
-    # Ensures that, if no NIC info was available, the server raises an
-    # exception.
-    #
-    def test_write_host_info_with_missing_nicinfo
-        @host_info['NICINFO'] = nil
-
-        assert_raise(Exception) { @browser.write_host_info(@host_info) }
-    end
-
-    # Ensures the browser can properly parse the CPU details.
-    #
-    def test_parse_cpu_info
-        @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "CPU\n" }
-        @session.should_receive(:write).with("CPUINFO?\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 { "ENDCPU\n" }
-        @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "ENDINFO\n" }
-
-        info = @browser.get_remote_info
-
-        assert_equal 3,info.keys.size, "Should contain four keys"
-        assert info.include?("CPUINFO")
-    end
-
-    # Ensures the browser can properly parse the CPU details of two CPUs.
-    #
-    def test_parse_cpu_info_with_two_entries
-        @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
-
-        # CPU 0
-        @session.should_receive(:readline).once().returns { "CPU\n" }
-        @session.should_receive(:write).with("CPUINFO?\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 { "ENDCPU\n" }
-        @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
-
-        # CPU 1
-        @session.should_receive(:readline).once().returns { "CPU\n" }
-        @session.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "key3=value3\n" }
-        @session.should_receive(:write).with("ACK key3\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "key4=value4\n" }
-        @session.should_receive(:write).with("ACK key4\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "ENDCPU\n" }
-        @session.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
-
-        @session.should_receive(:readline).once().returns { "ENDINFO\n" }
-
-        info = @browser.get_remote_info
-
-        assert_equal 3,info.keys.size, "Should contain four keys"
-        assert info.include?('CPUINFO')
-        assert_equal 2, info['CPUINFO'].size, "Should contain details for two CPUs"
-        assert_not_nil info['CPUINFO'][0]['key1']
-        assert_not_nil info['CPUINFO'][0]['key2']
-        assert_not_nil info['CPUINFO'][1]['key3']
-        assert_not_nil info['CPUINFO'][1]['key4']
-    end
-
-    # Ensures the browser can properly parse the details for a NIC.
-    #
-    def test_parse_nic_info
-        @session.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "NIC\n" }
-        @session.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "key1=value1\n" }
-        @session.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "key2=value2\n" }
-        @session.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "ENDNIC\n" }
-        @session.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length }
-        @session.should_receive(:readline).once().returns { "ENDINFO\n" }
-
-        info = @browser.get_remote_info
-
-        assert_equal 3,info.keys.size, "Should contain four keys"
-        assert info.include?("NICINFO")
-    end
-
-end
diff --git a/wui/src/lib/managed_node_configuration.rb b/wui/src/lib/managed_node_configuration.rb
new file mode 100644
index 0000000..aa8c711
--- /dev/null
+++ b/wui/src/lib/managed_node_configuration.rb
@@ -0,0 +1,49 @@
+# 
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce 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.
+
+# +ManagedNodeConfiguration+ takes in the description for a managed node and,
+# from that, generates the configuration file that is consumed the next time
+# the managed node starts up.
+#
+
+require 'stringio'
+
+$: << File.join(File.dirname(__FILE__), "../dutils")
+$: << File.join(File.dirname(__FILE__), "../")
+
+class ManagedNodeConfiguration
+  NIC_ENTRY_PREFIX='/files/etc/sysconfig/network-scripts'
+
+  def self.generate(host)
+    result = StringIO.new
+    
+    host.nics.each do |nic|
+      result.puts "rm #{NIC_ENTRY_PREFIX}/ifcfg-#{nic.iface_name}"
+      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{nic.iface_name}/DEVICE #{nic.iface_name}"
+      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{nic.iface_name}/IPADDR #{nic.ip_addr}"    if nic.ip_addr
+      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{nic.iface_name}/BOOTPROTO dhcp"           if nic.ip_addr == nil            
+      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{nic.iface_name}/BRIDGE #{nic.bridge}"     if nic.bridge       
+    end
+
+    result.puts "save"
+    
+    result.string
+  end
+end
+
diff --git a/wui/src/test/fixtures/nics.yml b/wui/src/test/fixtures/nics.yml
index 008cfb7..c31714a 100644
--- a/wui/src/test/fixtures/nics.yml
+++ b/wui/src/test/fixtures/nics.yml
@@ -6,6 +6,7 @@ one:
   usage_type: '1'
   bandwidth: 100
   host_id: 1
+  iface_name: eth0
 two:
   id: 2
   mac: 'AA:BB:CC:DD:EE:FF'
@@ -13,6 +14,7 @@ two:
   usage_type: '2'
   bandwidth: 1000
   host_id: 1
+  iface_name: eth1
 three:
   id: 3
   mac: '00:FF:11:EE:22:DD'
@@ -20,3 +22,4 @@ three:
   usage_type: '1'
   bandwidth: 10
   host_id: 2
+  iface_name: eth0
diff --git a/wui/src/test/unit/host_browser_awaken_test.rb b/wui/src/test/unit/host_browser_awaken_test.rb
new file mode 100755
index 0000000..5340e01
--- /dev/null
+++ b/wui/src/test/unit/host_browser_awaken_test.rb
@@ -0,0 +1,96 @@
+#!/usr/bin/ruby -Wall
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce 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_helper'
+require 'test/unit'
+require 'flexmock/test_unit'
+
+TESTING=true
+
+require 'host-browser'
+
+# +HostBrowserAwakenTest+ ensures that the host-browser daemon works correctly
+# during the identify phase of operation.
+#
+class HostBrowserAwakenTest < 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}/ipa/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',@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/test/unit/host_browser_identify_test.rb b/wui/src/test/unit/host_browser_identify_test.rb
new file mode 100755
index 0000000..e43507c
--- /dev/null
+++ b/wui/src/test/unit/host_browser_identify_test.rb
@@ -0,0 +1,304 @@
+#!/usr/bin/ruby -Wall
+#
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce 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_helper'
+
+require 'test/unit'
+require 'flexmock/test_unit'
+require 'dutils'
+
+TESTING=true
+
+require 'host-browser'
+
+# +HostBrowserIdentifyTest+ tests the host-browser server to ensure that it 
+# works correctly during the identify mode of operation.
+#
+class HostBrowserIdentifyTest < Test::Unit::TestCase
+  def setup
+    @connection = flexmock('connection')
+    @connection.should_receive(:peeraddr).at_least.once.returns { [nil,nil,nil,"192.168.2.255"] }
+
+    @browser = HostBrowser.new(@connection)
+    @browser.logfile = './unit-test.log'
+
+    # default host info
+    @host_info = {}
+    @host_info['UUID']     = 'node1'
+    @host_info['IPADDR']   = '192.168.2.2'
+    @host_info['HOSTNAME'] = 'prod.corp.com'
+    @host_info['ARCH']     = 'x86_64'
+    @host_info['MEMSIZE']  = '16384'
+    @host_info['DISABLED'] = '0'
+
+    @host_info['NUMCPUS']  = '2'
+
+    @host_info['CPUINFO'] = Array.new
+    @host_info['CPUINFO'][0] = {}
+    @host_info['CPUINFO'][0]['CPUNUM']   = '0'
+    @host_info['CPUINFO'][0]['CORENUM']  = '0'
+    @host_info['CPUINFO'][0]['NUMCORES'] = '2'
+    @host_info['CPUINFO'][0]['VENDOR']   = 'GenuineIntel'
+    @host_info['CPUINFO'][0]['MODEL']    = '15'
+    @host_info['CPUINFO'][0]['FAMILY']   = '6'
+    @host_info['CPUINFO'][0]['CPUIDLVL'] = '10'
+    @host_info['CPUINFO'][0]['SPEED']    = '3'
+    @host_info['CPUINFO'][0]['CACHE']    = '4096 kb'
+    @host_info['CPUINFO'][0]['FLAGS']    = 'fpu vme de pse tsc msr pae \
+            mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
+            fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
+            bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
+
+    @host_info['CPUINFO'][1] = {}
+    @host_info['CPUINFO'][1]['CPUNUM']   = '1'
+    @host_info['CPUINFO'][1]['CORENUM']  = '1'
+    @host_info['CPUINFO'][1]['NUMCORES'] = '2'
+    @host_info['CPUINFO'][1]['VENDOR']   = 'GenuineIntel'
+    @host_info['CPUINFO'][1]['MODEL']    = '15'
+    @host_info['CPUINFO'][1]['FAMILY']   = '6'
+    @host_info['CPUINFO'][1]['CPUIDLVL'] = '10'
+    @host_info['CPUINFO'][1]['SPEED']    = '3'
+    @host_info['CPUINFO'][1]['CACHE']    = '4096 kb'
+    @host_info['CPUINFO'][1]['FLAGS']    = 'fpu vme de pse tsc msr pae \
+            mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx \
+            fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs \
+            bts pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm'
+
+    @host_info['NICINFO'] = Array.new
+    @host_info['NICINFO'] << {        
+      'MAC'        => '00:11:22:33:44:55',
+      'BANDWIDTH'  => '100',
+      'IFACE_NAME' => 'eth0'}
+        
+    @host_info['NICINFO'] << {
+      'MAC'        => '00:77:11:77:19:65',
+      'BANDWIDTH'  => '100',
+      'IFACE_NAME' => 'eth01'}
+  end
+
+  # Ensures that the server is satisfied if the remote system is
+  # making a wakeup call.
+  #
+  def test_get_mode_with_awaken_request
+    @connection.should_receive(:write).with("MODE?\n").once().returns { |request| request.length }
+    @connection.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
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.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
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.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
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key1=value1\n" }
+    @connection.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+    @connection.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
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key1=value1\n" }
+    @connection.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key2=value2\n" }
+    @connection.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+    info = @browser.get_remote_info
+
+    assert_equal 4,info.keys.size, "Should contain four keys"
+    assert info.include?("IPADDR")
+    assert info.include?("HOSTNAME")
+    assert info.include?("key1")
+    assert info.include?("key2")
+  end
+
+  # Ensures that the server is fine when no UUID is present.
+  #
+  def test_write_host_info_with_missing_uuid
+    @host_info['UUID'] = nil
+
+    assert_nothing_raised { @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 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 no cpu info was available, the server raises an
+  # exception.
+  #
+  def test_write_host_info_with_missing_cpuinfo
+    @host_info['CPUINFO'] = nil
+
+    assert_raise(Exception) { @browser.write_host_info(@host_info) }
+  end
+
+  # Ensures that, if no NIC info was available, the server raises an
+  # exception.
+  #
+  def test_write_host_info_with_missing_nicinfo
+    @host_info['NICINFO'] = nil
+
+    assert_raise(Exception) { @browser.write_host_info(@host_info) }
+  end
+  
+  # Ensures that, if a NIC is present that was already submitted, it 
+  # doesn't get re-entered.
+  #
+  def test_write_host_info_with_duplicate_nic
+    # Values taken from the nics.yml fixture
+    @host_info['NICINFO'] << {
+      'MAC'        => '00:11:22:33:44:55',
+      'BANDWIDTH'  => '100',
+      'IFACE_NAME' => 'eth0'
+    }
+    
+    assert_nothing_raised { @browser.write_host_info(@host_info) }    
+    assert_equal 3, Host.find_by_hostname('prod.corp.com').nics.size, 'Expected three NICs.'
+  end
+
+  # Ensures the browser can properly parse the CPU details.
+  #
+  def test_parse_cpu_info
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "CPU\n" }
+    @connection.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key1=value1\n" }
+    @connection.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key2=value2\n" }
+    @connection.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDCPU\n" }
+    @connection.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+    info = @browser.get_remote_info
+
+    assert_equal 3,info.keys.size, "Should contain four keys"
+    assert info.include?("CPUINFO")
+  end
+
+  # Ensures the browser can properly parse the CPU details of two CPUs.
+  #
+  def test_parse_cpu_info_with_two_entries
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+
+    # CPU 0
+    @connection.should_receive(:readline).once().returns { "CPU\n" }
+    @connection.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key1=value1\n" }
+    @connection.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key2=value2\n" }
+    @connection.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDCPU\n" }
+    @connection.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
+
+    # CPU 1
+    @connection.should_receive(:readline).once().returns { "CPU\n" }
+    @connection.should_receive(:write).with("CPUINFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key3=value3\n" }
+    @connection.should_receive(:write).with("ACK key3\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key4=value4\n" }
+    @connection.should_receive(:write).with("ACK key4\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDCPU\n" }
+    @connection.should_receive(:write).with("ACK CPU\n").once().returns { |request| request.length }
+
+    @connection.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+    info = @browser.get_remote_info
+
+    assert_equal 3,info.keys.size, "Should contain four keys"
+    assert info.include?('CPUINFO')
+    assert_equal 2, info['CPUINFO'].size, "Should contain details for two CPUs"
+    assert_not_nil info['CPUINFO'][0]['key1']
+    assert_not_nil info['CPUINFO'][0]['key2']
+    assert_not_nil info['CPUINFO'][1]['key3']
+    assert_not_nil info['CPUINFO'][1]['key4']
+  end
+
+  # Ensures the browser can properly parse the details for a NIC.
+  #
+  def test_parse_nic_info
+    @connection.should_receive(:write).with("INFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "NIC\n" }
+    @connection.should_receive(:write).with("NICINFO?\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key1=value1\n" }
+    @connection.should_receive(:write).with("ACK key1\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "key2=value2\n" }
+    @connection.should_receive(:write).with("ACK key2\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDNIC\n" }
+    @connection.should_receive(:write).with("ACK NIC\n").once().returns { |request| request.length }
+    @connection.should_receive(:readline).once().returns { "ENDINFO\n" }
+
+    info = @browser.get_remote_info
+
+    assert_equal 3,info.keys.size, "Should contain four keys"
+    assert info.include?("NICINFO")
+  end
+end
diff --git a/wui/src/test/unit/managed_node_configuration_test.rb b/wui/src/test/unit/managed_node_configuration_test.rb
new file mode 100644
index 0000000..01b3fe4
--- /dev/null
+++ b/wui/src/test/unit/managed_node_configuration_test.rb
@@ -0,0 +1,87 @@
+# 
+# Copyright (C) 2008 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce 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.
+
+$:.unshift File.join(File.dirname(__FILE__),'..','lib')
+
+# require File.dirname(__FILE__) + '/../test/test_helper'
+require 'test/unit'
+require 'managed_node_configuration'
+require 'dutils'
+
+# Performs unit tests on the +ManagedNodeConfiguration+ class.
+#
+class ManagedNodeConfigurationTest < Test::Unit::TestCase
+  def setup
+    @host   = Host.new    
+  end
+
+  
+  # Ensures that network interfaces uses DHCP when no IP address is specified.
+  #
+  def test_generate_with_no_ip_address
+    @host.nics << Nic.new(:iface_name => 'eth0')
+    
+    expected = <<HERE
+rm /files/etc/sysconfig/network-scripts/ifcfg-eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/DEVICE eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BOOTPROTO dhcp
+save
+HERE
+    
+    result = ManagedNodeConfiguration.generate @host
+    
+    assert_equal expected, result
+  end
+  
+  # Ensures that network interfaces use the IP address when it's provided.
+  #
+  def test_generate_with_ip_address  
+    @host.nics << Nic.new(:iface_name => 'eth0', :ip_addr => '192.168.2.1')
+    
+    expected = <<HERE
+rm /files/etc/sysconfig/network-scripts/ifcfg-eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/DEVICE eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/IPADDR 192.168.2.1
+save
+HERE
+    
+    result = ManagedNodeConfiguration.generate @host 
+    
+    assert_equal expected, result
+  end
+  
+  # Ensures the bridge is added to the configuration if one is defined.
+  #
+  def test_generate_with_bridge
+    @host.nics << Nic.new(:iface_name => 'eth0', :bridge => 'ovirtbr0')
+  
+    expected = <<HERE
+rm /files/etc/sysconfig/network-scripts/ifcfg-eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/DEVICE eth0
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BOOTPROTO dhcp
+set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BRIDGE ovirtbr0
+save
+HERE
+    
+    result = ManagedNodeConfiguration.generate @host
+    
+    assert_equal expected, result
+  end
+  
+end
-- 
1.5.5.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]