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

[Ovirt-devel] [PATCH] The identify node phase now passes the interface name when identifying



You will need to do a rake db:migrate for this patch.

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/db/migrate/013_add_iface_name_to_nics.rb   |    9 +
 wui/src/host-browser/host-browser.rb               |  582 ++++++++++----------
 wui/src/host-browser/test-host-browser-identify.rb |  490 +++++++++--------
 6 files changed, 555 insertions(+), 532 deletions(-)
 create mode 100644 wui/src/db/migrate/013_add_iface_name_to_nics.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/db/migrate/013_add_iface_name_to_nics.rb b/wui/src/db/migrate/013_add_iface_name_to_nics.rb
new file mode 100644
index 0000000..c829c20
--- /dev/null
+++ b/wui/src/db/migrate/013_add_iface_name_to_nics.rb
@@ -0,0 +1,9 @@
+class AddIntfNameToNics < 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..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,@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-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
-- 
1.5.5.1


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