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

Darryl L. Pierce dpierce at redhat.com
Mon Aug 18 20:48:42 UTC 2008


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.

What this needs is integration with the WUI itself, to generate the file
when the admin modifies the NIC for the host.

Signed-off-by: Darryl L. Pierce <dpierce at 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/host-browser/host-browser.rb               |  582 ++++++++++----------
 wui/src/host-browser/test-host-browser-identify.rb |  490 +++++++++--------
 wui/src/lib/managed_node_configuration.rb          |   58 ++
 .../test/unit/managed_node_configuration_test.rb   |   88 +++
 7 files changed, 692 insertions(+), 532 deletions(-)
 create mode 100644 wui/src/lib/managed_node_configuration.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/host-browser/host-browser.rb b/wui/src/host-browser/host-browser.rb
index 881b2ae..26981fd 100755
--- a/wui/src/host-browser/host-browser.rb
+++ b/wui/src/host-browser/host-browser.rb
@@ -39,361 +39,369 @@ $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)
         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, at keytab_filename)
+    end
 
-            File.chmod(0644, at 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-identify.rb b/wui/src/host-browser/test-host-browser-identify.rb
index 7e672ce..e25497f 100755
--- a/wui/src/host-browser/test-host-browser-identify.rb
+++ b/wui/src/host-browser/test-host-browser-identify.rb
@@ -27,257 +27,259 @@ 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 \
+  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 \
+    @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
+    @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 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/lib/managed_node_configuration.rb b/wui/src/lib/managed_node_configuration.rb
new file mode 100644
index 0000000..0bb34f0
--- /dev/null
+++ b/wui/src/lib/managed_node_configuration.rb
@@ -0,0 +1,58 @@
+# 
+# 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.
+
+# +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
+  @network_interfaces
+  @file = nil
+  
+  attr_accessor :hostname
+  
+  def initialize(host)
+    @host = host
+  end
+  
+  NIC_ENTRY_PREFIX='/files/etc/sysconfig/network-scripts'
+
+  def generate    
+    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/unit/managed_node_configuration_test.rb b/wui/src/test/unit/managed_node_configuration_test.rb
new file mode 100644
index 0000000..bfbfdac
--- /dev/null
+++ b/wui/src/test/unit/managed_node_configuration_test.rb
@@ -0,0 +1,88 @@
+# 
+# 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.
+
+$:.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    
+    @config = ManagedNodeConfiguration.new(@host)
+  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 = @config.generate
+    
+    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 = @config.generate
+    
+    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 = @config.generate
+    
+    assert_equal expected, result
+  end
+  
+end
-- 
1.5.5.1




More information about the ovirt-devel mailing list