[Ovirt-devel] [PATCH server] Replaced the config scripts with configuration encoding.

Darryl L. Pierce dpierce at redhat.com
Mon Oct 6 17:39:33 UTC 2008


*** NOTE ***
This patch is a request for comments. I'm looking for some feedback on the encoding
strategy I'm using below. The goal is to get away from using embedded scripts and to
instead just describe the desired state to the node.
*** NOTE ***

Rather than sending the node a series of scripts that load
kernel modules, or are tightly coupled to tools like augeas,
this patch introduces an encoding scheme for data.

A line that begins with "kmod" describes a kernel module that
needs to be loaded. It will containing the module's name, an
optional alias for the module, and then the module options
if such are required.

A line that begins with "ifcfg" describes an network
interface. It will contain the mac address and interface name,
followed by all needed configuration values to bring the
interface up.

Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 src/app/models/bonding.rb                          |    1 +
 src/lib/managed_node_configuration.rb              |   72 +++++++++------
 src/test/fixtures/bondings.yml                     |    8 ++-
 src/test/fixtures/bondings_nics.yml                |    8 ++
 src/test/fixtures/hosts.yml                        |   10 ++
 src/test/fixtures/nics.yml                         |   14 +++
 .../functional/managed_node_configuration_test.rb  |   94 ++++++++------------
 7 files changed, 118 insertions(+), 89 deletions(-)

diff --git a/src/app/models/bonding.rb b/src/app/models/bonding.rb
index 941e2cd..7bef2f8 100644
--- a/src/app/models/bonding.rb
+++ b/src/app/models/bonding.rb
@@ -38,6 +38,7 @@ class Bonding < ActiveRecord::Base
 
   belongs_to :host
   belongs_to :bonding_type
+  belongs_to :boot_type
 
   has_and_belongs_to_many :nics,
     :join_table  => 'bondings_nics',
diff --git a/src/lib/managed_node_configuration.rb b/src/lib/managed_node_configuration.rb
index 4ade235..7a1ceac 100644
--- a/src/lib/managed_node_configuration.rb
+++ b/src/lib/managed_node_configuration.rb
@@ -23,36 +23,57 @@
 
 require 'stringio'
 
+# +ManagedNodeConfiguration+ generates a configuration file for an oVirt node
+# based on information about the hardware submitted by the node and the 
+# configuration details held in the database.
+# 
+# The configuration is returned as a series of encoded lines.
+# 
+# For a kernel module, the formation of the line is as follows:
+# 
+# kmod=[module name]|[module alias]|[module options]
+# 
+# An example would be for loading the +bonding+ kernel module to setup a bonded
+# interface for load balancing. In this example, the bonded interface would be
+# named +failover0+ on the node:
+# 
+# kmod=bonding|failover0|mode=2 miimon=100 downdelay=200
+#  
+# For a network interface (including a bonded interface) an example would be:
+# 
+# ifcfg=00:11:22:33:44|eth0|BOOTPROTO=dhcp|bridge=ovirtbr0|ONBOOT=yes
+# 
+# In this line, the network interface +eth0+ has a hardware MAC address of 
+# +00:11:22:33:44+. It will use DHCP for retrieving it's IP address details, 
+# and will use the +ovirtbr0+ interface as a bridge.
+#
 class ManagedNodeConfiguration
   NIC_ENTRY_PREFIX='/files/etc/sysconfig/network-scripts'
 
   def self.generate(host, macs)
     result = StringIO.new
 
-    result.puts "#!/bin/bash"
     result.puts "# THIS FILE IS GENERATED!"
 
     # first process any bondings that're defined
     unless host.bondings.empty?
-      result.puts "cat <<\EOF > /var/tmp/pre-config-script"
-      result.puts "#!/bin/bash"
-      result.puts "# THIS FILE IS GENERATED!"
-
       host.bondings.each do |bonding|
-        result.puts "/sbin/modprobe bonding mode=#{bonding.bonding_type.mode}"
+        result.puts "kmod=bonding|#{bonding.interface_name}|mode=#{bonding.bonding_type.mode} miimon=100 downdelay=200"
       end
-
-      result.puts "EOF"
     end
 
     # now process the network interfaces  and bondings
-    result.puts "cat <<\EOF > /var/tmp/node-augtool"
 
     host.bondings.each do |bonding|
-      result.puts "rm #{NIC_ENTRY_PREFIX}/ifcfg-#{bonding.interface_name}"
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{bonding.interface_name}/DEVICE #{bonding.interface_name}"
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{bonding.interface_name}/IPADDR #{bonding.ip_addr}" if bonding.ip_addr
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{bonding.interface_name}/ONBOOT yes"
+      entry = "ifcfg=none|#{bonding.interface_name}"
+      
+      if bonding.ip_addr == nil || bonding.ip_addr.empty?
+        entry += "|BOOTPROTO=dhcp" 
+      else
+        entry += "|BOOTPROTO=static|IPADDR=#{bonding.ip_addr}|NETMASK=#{bonding.netmask}|BROADCAST=#{bonding.broadcast}" 
+      end
+      
+      result.puts "#{entry}|ONBOOT=yes"
 
       bonding.nics.each do |nic|
         process_nic result, nic, macs, bonding
@@ -66,9 +87,6 @@ class ManagedNodeConfiguration
       end
     end
 
-    result.puts "save"
-    result.puts "EOF"
-
     result.string
   end
 
@@ -78,24 +96,18 @@ class ManagedNodeConfiguration
     iface_name = macs[nic.mac]
 
     if iface_name
-      result.puts "rm #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}"
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/DEVICE #{iface_name}"
+      entry = "ifcfg=#{nic.mac}|#{iface_name}"
 
       if bonding
-        result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/MASTER #{bonding.interface_name}"
-        result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/SLAVE yes"
+        entry += "|MASTER=#{bonding.interface_name}|SLAVE=yes" 
       else
-        result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/BOOTPROTO #{nic.boot_type.proto}"
-
-        if nic.boot_type.proto == 'static'
-          result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/IPADDR #{nic.ip_addr}"
-          result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/NETMASK #{nic.netmask}"
-          result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/BROADCAST #{nic.broadcast}"
-        end
+        entry += "|BOOTPROTO=#{nic.boot_type.proto}" 
+        entry += "|IPADDR=#{nic.ip_addr}|NETMASK=#{nic.netmask}|BROADCAST=#{nic.broadcast}" if nic.boot_type.proto == 'static'
+        entry += "|BRIDGE=#{nic.bridge}" if nic.bridge
       end
-
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/BRIDGE #{nic.bridge}"     if nic.bridge
-      result.puts "set #{NIC_ENTRY_PREFIX}/ifcfg-#{iface_name}/ONBOOT yes"
+      entry += "|ONBOOT=yes"
     end
+    
+    result.puts entry if defined? entry
   end
 end
diff --git a/src/test/fixtures/bondings.yml b/src/test/fixtures/bondings.yml
index c2a47b5..7023e08 100644
--- a/src/test/fixtures/bondings.yml
+++ b/src/test/fixtures/bondings.yml
@@ -1,6 +1,6 @@
 mailservers_managed_node_bonding:
     name: Production Network
-    interface_name: bond0
+    interface_name: mailbonding0
     bonding_type_id: <%= Fixtures.identify(:link_aggregation_bonding_type) %>
     host_id: <%= Fixtures.identify(:mailservers_managed_node) %>
     ip_addr: 172.31.0.15
@@ -8,3 +8,9 @@ mailservers_managed_node_bonding:
     broadcast: 172.31.0.255
     arp_ping_address: 172.31.0.100
     arp_interval: 0
+
+mediaserver_managed_node_bonding:
+    name: Fileserver Network
+    interface_name: mediabonding0
+    bonding_type_id: <%= Fixtures.identify(:link_aggregation_bonding_type) %>
+    host_id: <%= Fixtures.identify(:mediaserver_managed_node) %>
diff --git a/src/test/fixtures/bondings_nics.yml b/src/test/fixtures/bondings_nics.yml
index 11a3d1a..607ff8b 100644
--- a/src/test/fixtures/bondings_nics.yml
+++ b/src/test/fixtures/bondings_nics.yml
@@ -5,3 +5,11 @@ mailservers_managed_node_bonding_nic_1:
 mailservers_managed_node_bonding_nic_2:
     bonding_id: <%= Fixtures.identify(:mailservers_managed_node_bonding) %>
     nic_id: <%= Fixtures.identify(:mailserver_nic_two) %>
+
+mediaservers_managed_node_bonding_nic_1:
+    bonding_id: <%= Fixtures.identify(:mediaserver_managed_node_bonding) %>
+    nic_id: <%= Fixtures.identify(:mediaserver_nic_one) %>
+
+mediaservers_managed_node_bonding_nic_2:
+    bonding_id: <%= Fixtures.identify(:mediaserver_managed_node_bonding) %>
+    nic_id: <%= Fixtures.identify(:mediaserver_nic_two) %>
diff --git a/src/test/fixtures/hosts.yml b/src/test/fixtures/hosts.yml
index 5b8af15..28282c2 100644
--- a/src/test/fixtures/hosts.yml
+++ b/src/test/fixtures/hosts.yml
@@ -125,3 +125,13 @@ buildserver_managed_node:
     is_disabled: 0
     hypervisor_type: 'kvm'
     hardware_pool_id: <%= Fixtures.identify(:prodops_pool) %>
+
+mediaserver_managed_node:
+    uuid: '6293acd9-2784-11dc-9387-001558c41534'
+    hostname: 'build.mynetwork.com'
+    arch: 'x86_64'
+    memory: 65536
+    is_disabled: 0
+    hypervisor_type: 'kvm'
+    hardware_pool_id: <%= Fixtures.identify(:prodops_pool) %>
+
diff --git a/src/test/fixtures/nics.yml b/src/test/fixtures/nics.yml
index ccf71d2..5b2cecc 100644
--- a/src/test/fixtures/nics.yml
+++ b/src/test/fixtures/nics.yml
@@ -78,3 +78,17 @@ buildserver_nic_two:
     broadcast: '172.31.0.255'
     host_id: <%= Fixtures.identify(:buildserver_managed_node) %>
     boot_type_id: <%= Fixtures.identify(:boot_type_static_ip) %>
+
+mediaserver_nic_one:
+    mac: '07:17:19:65:03:32'
+    usage_type: '1'
+    bandwidth: 100
+    host_id: <%= Fixtures.identify(:mediaserver_managed_node) %>
+    boot_type_id: <%= Fixtures.identify(:boot_type_dhcp) %>
+
+mediaserver_nic_two:
+    mac: '07:17:19:65:03:31'
+    usage_type: '1'
+    bandwidth: 100
+    host_id: <%= Fixtures.identify(:mediaserver_managed_node) %>
+    boot_type_id: <%= Fixtures.identify(:boot_type_dhcp) %>
diff --git a/src/test/functional/managed_node_configuration_test.rb b/src/test/functional/managed_node_configuration_test.rb
index b5a7ec5..0cad09b 100644
--- a/src/test/functional/managed_node_configuration_test.rb
+++ b/src/test/functional/managed_node_configuration_test.rb
@@ -36,6 +36,7 @@ class ManagedNodeConfigurationTest < Test::Unit::TestCase
     @host_with_ip_address = hosts(:ldapserver_managed_node)
     @host_with_multiple_nics = hosts(:buildserver_managed_node)
     @host_with_bondings = hosts(:mailservers_managed_node)
+    @host_with_dhcp_bondings = hosts(:mediaserver_managed_node)
   end
 
   # Ensures that network interfaces uses DHCP when no IP address is specified.
@@ -44,15 +45,8 @@ class ManagedNodeConfigurationTest < Test::Unit::TestCase
     nic = @host_with_dhcp_card.nics.first
 
     expected = <<-HERE
-#!/bin/bash
 # THIS FILE IS GENERATED!
-cat <<\EOF > /var/tmp/node-augtool
-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 #{nic.boot_type.proto}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/ONBOOT yes
-save
-EOF
+ifcfg=#{nic.mac}|eth0|BOOTPROTO=dhcp|ONBOOT=yes
     HERE
 
     result = ManagedNodeConfiguration.generate(
@@ -69,19 +63,8 @@ EOF
     nic = @host_with_ip_address.nics.first
 
     expected = <<-HERE
-#!/bin/bash
 # THIS FILE IS GENERATED!
-cat <<\EOF > /var/tmp/node-augtool
-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 #{nic.boot_type.proto}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/IPADDR #{nic.ip_addr}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/NETMASK #{nic.netmask}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BROADCAST #{nic.broadcast}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BRIDGE ovirtbr0
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/ONBOOT yes
-save
-EOF
+ifcfg=#{nic.mac}|eth0|BOOTPROTO=#{nic.boot_type.proto}|IPADDR=#{nic.ip_addr}|NETMASK=#{nic.netmask}|BROADCAST=#{nic.broadcast}|BRIDGE=#{nic.bridge}|ONBOOT=yes
     HERE
 
     result = ManagedNodeConfiguration.generate(
@@ -99,22 +82,9 @@ EOF
     nic2 = @host_with_multiple_nics.nics[1]
 
     expected = <<-HERE
-#!/bin/bash
 # THIS FILE IS GENERATED!
-cat <<\EOF > /var/tmp/node-augtool
-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 #{nic1.boot_type.proto}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/IPADDR #{nic1.ip_addr}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/NETMASK #{nic1.netmask}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BROADCAST #{nic1.broadcast}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/ONBOOT yes
-rm /files/etc/sysconfig/network-scripts/ifcfg-eth1
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/DEVICE eth1
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/BOOTPROTO #{nic2.boot_type.proto}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/ONBOOT yes
-save
-EOF
+ifcfg=#{nic1.mac}|eth0|BOOTPROTO=#{nic1.boot_type.proto}|IPADDR=#{nic1.ip_addr}|NETMASK=#{nic1.netmask}|BROADCAST=#{nic1.broadcast}|ONBOOT=yes
+ifcfg=#{nic2.mac}|eth1|BOOTPROTO=#{nic2.boot_type.proto}|ONBOOT=yes
     HERE
 
     result = ManagedNodeConfiguration.generate(
@@ -137,30 +107,11 @@ EOF
     nic2 = bonding.nics[1]
 
     expected = <<-HERE
-#!/bin/bash
 # THIS FILE IS GENERATED!
-cat <<\EOF > /var/tmp/pre-config-script
-#!/bin/bash
-# THIS FILE IS GENERATED!
-/sbin/modprobe bonding mode=#{bonding.bonding_type.mode}
-EOF
-cat <<\EOF > /var/tmp/node-augtool
-rm /files/etc/sysconfig/network-scripts/ifcfg-#{bonding.interface_name}
-set /files/etc/sysconfig/network-scripts/ifcfg-#{bonding.interface_name}/DEVICE #{bonding.interface_name}
-set /files/etc/sysconfig/network-scripts/ifcfg-#{bonding.interface_name}/IPADDR 172.31.0.15
-set /files/etc/sysconfig/network-scripts/ifcfg-#{bonding.interface_name}/ONBOOT yes
-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/MASTER #{bonding.interface_name}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/SLAVE yes
-set /files/etc/sysconfig/network-scripts/ifcfg-eth0/ONBOOT yes
-rm /files/etc/sysconfig/network-scripts/ifcfg-eth1
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/DEVICE eth1
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/MASTER #{bonding.interface_name}
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/SLAVE yes
-set /files/etc/sysconfig/network-scripts/ifcfg-eth1/ONBOOT yes
-save
-EOF
+kmod=bonding|#{bonding.interface_name}|mode=#{bonding.bonding_type.mode} miimon=100 downdelay=200
+ifcfg=none|#{bonding.interface_name}|BOOTPROTO=static|IPADDR=#{bonding.ip_addr}|NETMASK=#{bonding.netmask}|BROADCAST=#{bonding.broadcast}|ONBOOT=yes
+ifcfg=#{nic1.mac}|eth0|MASTER=#{bonding.interface_name}|SLAVE=yes|ONBOOT=yes
+ifcfg=#{nic2.mac}|eth1|MASTER=#{bonding.interface_name}|SLAVE=yes|ONBOOT=yes
 HERE
 
     result = ManagedNodeConfiguration.generate(
@@ -173,4 +124,31 @@ HERE
     assert_equal expected, result
   end
 
+  # Ensures that the generated bonding supports DHCP boot protocol.
+  #
+  def test_generate_with_dhcp_bonding
+    bonding = @host_with_dhcp_bondings.bondings.first
+
+    bonding.ip_addr=nil
+    nic1 = bonding.nics[0]
+    nic2 = bonding.nics[1]
+
+    expected = <<-HERE
+# THIS FILE IS GENERATED!
+kmod=bonding|#{bonding.interface_name}|mode=#{bonding.bonding_type.mode} miimon=100 downdelay=200
+ifcfg=none|#{bonding.interface_name}|BOOTPROTO=dhcp|ONBOOT=yes
+ifcfg=#{nic1.mac}|eth0|MASTER=#{bonding.interface_name}|SLAVE=yes|ONBOOT=yes
+ifcfg=#{nic2.mac}|eth1|MASTER=#{bonding.interface_name}|SLAVE=yes|ONBOOT=yes
+HERE
+
+    result = ManagedNodeConfiguration.generate(
+      @host_with_dhcp_bondings,
+      {
+        "#{nic1.mac}" => 'eth0',
+        "#{nic2.mac}" => 'eth1'
+      })
+
+    assert_equal expected, result
+  end
+
 end
-- 
1.5.5.1




More information about the ovirt-devel mailing list