diff --git a/lib/puppet/provider/interface/redhat.rb b/lib/puppet/provider/interface/redhat.rb index 8d7d09ca3..1f269f0ca 100644 --- a/lib/puppet/provider/interface/redhat.rb +++ b/lib/puppet/provider/interface/redhat.rb @@ -2,6 +2,8 @@ require 'puppet/provider/parsedfile' require 'erb' Puppet::Type.type(:interface).provide(:redhat) do + INTERFACE_DIR = "/etc/sysconfig/network-scripts" + confine :exists => INTERFACE_DIR defaultfor :operatingsystem => [:fedora, :centos, :redhat] # Create the setter/gettor methods to match the model. @@ -32,14 +34,32 @@ LOOPBACKDUMMY # maximum number of aliases per interface MAX_ALIASES_PER_IFACE = 10 - INTERFACE_DIR = "/etc/sysconfig/network-scripts" @@dummies = [] @@aliases = Hash.new { |hash, key| hash[key] = [] } + # calculate which dummy interfaces are currently already in + # use prior to needing to call self.next_dummy later on. + def self.instances + # parse all of the config files at once + Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).collect do |file| + + record = parse(file) + + # store the existing dummy interfaces + if record[:interface_type] == :dummy + @@dummies << record[:ifnum] unless @@dummies.include?(record[:ifnum]) + end + + if record[:interface_type] == :alias + @@aliases[record[:interface]] << record[:ifnum] + end + new(record) + end + end + # return the next avaliable dummy interface number, in the case where # ifnum is not manually specified - def self.next_dummy MAX_DUMMIES.times do |i| unless @@dummies.include?(i.to_s) @@ -60,110 +80,6 @@ LOOPBACKDUMMY end end - # calculate which dummy interfaces are currently already in - # use prior to needing to call self.next_dummy later on. - def self.prefetch - # parse all of the config files at once - Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).each do |file| - - record = parse(file) - - # store the existing dummy interfaces - if record[:interface_type] == :dummy - @@dummies << record[:ifnum] - end - - if record[:interface_type] == :alias - @@aliases[record[:interface]] << record[:ifnum] - end - end - end - - def create - @model.class.validproperties.each do |property| - if value = @model.should(property) - @property_hash[property] = value - end - end - @property_hash[:name] = @model.name - - return (@model.class.name.to_s + "_created").intern - end - - def destroy - File.unlink(@model[:target]) - end - - def exists? - FileTest.exists?(@model[:target]) - end - - # generate the content for the interface file, so this is dependent - # on whether we are adding an alias to a real interface, or a loopback - # address (also dummy) on linux. For linux it's quite involved, and we - # will use an ERB template - def generate - # choose which template to use for the interface file, based on - # the interface type - case @model.should(:interface_type) - when :loopback - return LOOPBACK_TEMPLATE.result(binding) - when :alias - return ALIAS_TEMPLATE.result(binding) - end - end - - # Where should the file be written out? - # This defaults to INTERFACE_DIR/ifcfg-, but can have a - # more symbolic name by setting interface_desc in the type. - def file_path - @model[:interface_desc] ||= @model[:name] - return File.join(INTERFACE_DIR, "ifcfg-" + @model[:interface_desc]) - - end - - # create the device name, so this based on the IP, and interface + type - def device - case @model.should(:interface_type) - when :loopback - @property_hash[:ifnum] ||= self.class.next_dummy - return "dummy" + @property_hash[:ifnum] - when :alias - @property_hash[:ifnum] ||= self.class.next_alias(@model[:interface]) - return @model[:interface] + ":" + @property_hash[:ifnum] - end - end - - # whether the device is to be brought up on boot or not. converts - # the true / false of the type, into yes / no values respectively - # writing out the ifcfg-* files - def on_boot - case @property_hash[:onboot].to_s - when "true" - return "yes" - when "false" - return "no" - else - return "neither" - end - end - - # Write the new file out. - def flush - # Don't flush to disk if we're removing the config. - return if @model.should(:ensure) == :absent - - @property_hash.each do |name, val| - if val == :absent - raise ArgumentError, "Propety %s must be provided" % val - end - end - - File.open(@model[:target], "w") do |f| - f.puts generate() - end - end - # base the ifnum, for dummy / loopback interface in linux # on the last octect of the IP address @@ -198,7 +114,7 @@ LOOPBACKDUMMY # creating these opts[:ifnum] = opts[:device].sub("dummy",'') - @@dummies << opts[:ifnum].to_s + @@dummies << opts[:ifnum].to_s unless @@dummies.include?(opts[:ifnum].to_s) else opts[:interface_type] = :normal opts[:interface] = opts[:device] @@ -233,8 +149,102 @@ LOOPBACKDUMMY end + # Prefetch our interface list, yo. + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + + def create + @resource.class.validproperties.each do |property| + if value = @resource.should(property) + @property_hash[property] = value + end + end + @property_hash[:name] = @resource.name + + return (@resource.class.name.to_s + "_created").intern + end + + def destroy + File.unlink(@resource[:target]) + end + + def exists? + FileTest.exists?(@resource[:target]) + end + + # generate the content for the interface file, so this is dependent + # on whether we are adding an alias to a real interface, or a loopback + # address (also dummy) on linux. For linux it's quite involved, and we + # will use an ERB template + def generate + # choose which template to use for the interface file, based on + # the interface type + case @resource.should(:interface_type) + when :loopback + return LOOPBACK_TEMPLATE.result(binding) + when :alias + return ALIAS_TEMPLATE.result(binding) + end + end + + # Where should the file be written out? + # This defaults to INTERFACE_DIR/ifcfg-, but can have a + # more symbolic name by setting interface_desc in the type. + def file_path + @resource[:interface_desc] ||= @resource[:name] + return File.join(INTERFACE_DIR, "ifcfg-" + @resource[:interface_desc]) + + end + + # create the device name, so this based on the IP, and interface + type + def device + case @resource.should(:interface_type) + when :loopback + @property_hash[:ifnum] ||= self.class.next_dummy + return "dummy" + @property_hash[:ifnum] + when :alias + @property_hash[:ifnum] ||= self.class.next_alias(@resource[:interface]) + return @resource[:interface] + ":" + @property_hash[:ifnum] + end + end + + # whether the device is to be brought up on boot or not. converts + # the true / false of the type, into yes / no values respectively + # writing out the ifcfg-* files + def on_boot + case @property_hash[:onboot].to_s + when "true" + return "yes" + when "false" + return "no" + else + return "neither" + end + end + + # Write the new file out. + def flush + # Don't flush to disk if we're removing the config. + return if @resource.should(:ensure) == :absent + + @property_hash.each do |name, val| + if val == :absent + raise ArgumentError, "Propety %s must be provided" % val + end + end + + File.open(@resource[:target], "w") do |f| + f.puts generate() + end + end + def prefetch - @property_hash = self.class.parse(@model[:target]) + @property_hash = self.class.parse(@resource[:target]) end end diff --git a/lib/puppet/provider/interface/sunos.rb b/lib/puppet/provider/interface/sunos.rb index 0290aa209..abe9dd8c6 100644 --- a/lib/puppet/provider/interface/sunos.rb +++ b/lib/puppet/provider/interface/sunos.rb @@ -12,10 +12,7 @@ Puppet::Type.type(:interface).provide(:sunos, # Two types of lines: # the first line does not start with 'addif' # the rest do - - record_line :sunos, :fields => %w{interface_type name ifopts onboot}, :rts => true, :absent => "", :block_eval => :instance do - # Parse our interface line def process(line) details = {:ensure => :present} @@ -80,6 +77,14 @@ Puppet::Type.type(:interface).provide(:sunos, %{} end + # Get a list of interface instances. + def self.instances + Dir.glob("/etc/hostname.*").collect do |file| + # We really only expect one record from each file + parse(file).shift + end.collect { |record| new(record) } + end + def self.match(hash) # see if we can match the has against an existing object if model.find { |obj| obj.value(:name) == hash[:name] } @@ -89,10 +94,22 @@ Puppet::Type.type(:interface).provide(:sunos, end end + # Prefetch our interface list, yo. + def self.prefetch(resources) + instances.each do |prov| + if resource = resources[prov.name] + resource.provider = prov + end + end + end + # Where should the file be written out? Can be overridden by setting # :target in the model. def file_path - return File.join("/etc", "hostname." + @model[:interface]) + unless @resource[:interface] + raise ArgumentError, "You must provide the interface name on Solaris" + end + return File.join("/etc", "hostname." + @resource[:interface]) end end diff --git a/lib/puppet/type/interface.rb b/lib/puppet/type/interface.rb index 206776260..e0ad34761 100644 --- a/lib/puppet/type/interface.rb +++ b/lib/puppet/type/interface.rb @@ -50,7 +50,7 @@ Puppet::Type.newtype(:interface) do newparam(:target) do desc "The path to the file this resource creates." - defaultto { @parent.provider.file_path } + defaultto { @resource.provider.file_path } end end diff --git a/test/ral/types/interface.rb b/test/ral/types/interface.rb new file mode 100755 index 000000000..66425deb2 --- /dev/null +++ b/test/ral/types/interface.rb @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby + +$:.unshift("../../lib") if __FILE__ =~ /\.rb$/ + +require 'puppettest' +require 'mocha' + +class TestInterfaceType < PuppetTest::TestCase + include PuppetTest + + def setup + super + @type = Puppet::Type.type(:interface) + end + + def test_prefetch + interface = @type.create(:name => "127.0.0.1", :interface => "lo0", :check => :all) + + @type.suitableprovider.each do |provider| + assert_nothing_raised("Could not prefetch interfaces from %s provider" % provider.name) do + provider.prefetch("eth0" => interface) + end + end + end + + def test_instances + @type.suitableprovider.each do |provider| + list = nil + assert_nothing_raised("Could not get instance list from %s" % provider.name) do + list = provider.instances + end + assert(list.length > 0, "Did not get any instances from %s" % provider.name) + list.each do |interface| + assert_instance_of(provider, interface, "%s provider returned something other than a provider instance" % provider.name) + end + end + end +end + +# $Id$