diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-11-13 02:07:07 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-11-13 02:07:07 +0000 |
| commit | bb80c1bb2c977fe462fa9d74031929547c2bbc40 (patch) | |
| tree | 5774dab49b96db6cfb59c7316563a527612f495d /lib/puppet/provider/port | |
| parent | 25b575fcdd588a619a89ac3fce474f4f35de3fb1 (diff) | |
| download | puppet-bb80c1bb2c977fe462fa9d74031929547c2bbc40.tar.gz puppet-bb80c1bb2c977fe462fa9d74031929547c2bbc40.tar.xz puppet-bb80c1bb2c977fe462fa9d74031929547c2bbc40.zip | |
Ports are still broken, but I need to work on something else while I am thinking about how to fix them. Stupid /etc/services.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1863 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/provider/port')
| -rwxr-xr-x | lib/puppet/provider/port/parsed.rb | 242 |
1 files changed, 138 insertions, 104 deletions
diff --git a/lib/puppet/provider/port/parsed.rb b/lib/puppet/provider/port/parsed.rb index d65a0777f..510b461df 100755 --- a/lib/puppet/provider/port/parsed.rb +++ b/lib/puppet/provider/port/parsed.rb @@ -1,135 +1,169 @@ require 'puppet/provider/parsedfile' -Puppet::Type.type(:port).provide :parsed, :parent => Puppet::Provider::ParsedFile do - - @filetype = Puppet::FileType.filetype(:flat) - @path = "/etc/services" - - # Parse a services file - # - # This method also stores existing comments, and it stores all port - # info in order, mostly so that comments are retained in the order - # they were written and in proximity to the same ports. - def self.parse(text) - count = 0 - instances = [] - namehash = {} # For merging - text.chomp.split("\n").each { |line| - hash = {} - case line - when /^#/, /^\s*$/: - # add comments and blank lines to the list as they are - instances << line - else - if line.sub!(/^(\S+)\s+(\d+)\/(\w+)\s*/, '') - hash[:name] = $1 - hash[:number] = $2 - hash[:protocols] = [$3] - - unless line == "" - line.sub!(/^([^#]+)\s*/) do |value| - aliases = $1 - - # Remove any trailing whitespace - aliases.strip! - unless aliases =~ /^\s*$/ - hash[:alias] = aliases.split(/\s+/) - end - - "" - end - - line.sub!(/^\s*#\s*(.+)$/) do |value| - desc = $1 - unless desc =~ /^\s*$/ - hash[:description] = desc.sub(/\s*$/, '') - end - - "" - end - end - else - if line =~ /^\s+\d+/ and - Facter["operatingsystem"].value == "Darwin" - #Puppet.notice "Skipping wonky OS X port entry %s" % - # line.inspect - next - end - raise Puppet::Error, "Could not match '%s'" % line - end - - # If there's already a service with this name, then check - # to see if the only difference is the proto; if so, just - # add our proto and walk away - if obj = namehash[hash[:name]] - if portmerge(obj, hash) - next - end - end +services = nil +case Facter.value(:operatingsystem) +when "Solaris": services = "/etc/inet/services" +else + services = "/etc/services" +end - instances << hash - namehash[hash[:name]] = hash +Puppet::Type.type(:port).provide(:parsed, + :parent => Puppet::Provider::ParsedFile, + :default_target => services, + :filetype => :flat +) do + text_line :comment, :match => /^\s*#/ + text_line :blank, :match => /^\s*$/ + + # We're cheating horribly here -- we don't support ddp, because it assigns + # the same number to already-used names, and the same name to different + # numbers. + text_line :ddp, :match => /^\S+\s+\d+\/ddp/ + + # Also, just ignore the lines on OS X that don't have service names. + text_line :funky_darwin, :match => /^\s+\d+\// + + # We have to manually parse the line, since it's so darn complicated. + record_line :parsed, :fields => %w{name port protocols alias} do |line| + if line =~ /\/ddp/ + raise "missed ddp in %s" % line + end + # The record might contain multiple port lines separated by \n. + hashes = line.split("\n").collect { |l| parse_port(l) } - count += 1 - end - } + # It's easy if there's just one hash. + if hashes.length == 1 + return hashes.shift + end - return instances + # Else, merge the two records into one. + return port_merge(*hashes) end - def self.portmerge(base, hash) - unless base.has_key?(:protocols) - return false + # Override how we split into lines, so that we always treat both protocol + # lines as a single line. This drastically simplifies merging the two lines + # into one record. + def self.lines(text) + names = {} + lines = [] + + # We organize by number, because that's apparently how the ports work. + # You'll never be able to use Puppet to manage multiple entries + # with the same name but different numbers, though. + text.split("\n").each do |line| + if line =~ /^([-\w]+)\s+(\d+)\/[^d]/ # We want to skip ddp proto stuff + names[$1] ||= [] + names[$1] << line + lines << [:special, $1] + else + lines << line + end end - # This method is only called from parsing, so we only worry - # about 'is' values. - proto = base[:protocols] + # Now, return each line in order, but join the ones with the same name + lines.collect do |line| + if line.is_a?(Array) + name = line[1] + if names[name] + t = names[name].join("\n") + names.delete(name) + t + end + else + line + end + end.reject { |l| l.nil? } + end + + # Parse a single port line, returning a hash. + def self.parse_port(line) + hash = {} + if line.sub!(/^(\S+)\s+(\d+)\/(\w+)\s*/, '') + hash[:name] = $1 + hash[:number] = $2 + hash[:protocols] = [$3] + + unless line == "" + line.sub!(/^([^#]+)\s*/) do |value| + aliases = $1 + + # Remove any trailing whitespace + aliases.strip! + unless aliases =~ /^\s*$/ + hash[:alias] = aliases.split(/\s+/) + end - if proto.nil? or proto == :absent - # We are an unitialized object; we've got 'should' - # values but no 'is' values - return false - end + "" + end - # If this is happening, our object exists - base[:ensure] = :present + line.sub!(/^\s*#\s*(.+)$/) do |value| + desc = $1 + unless desc =~ /^\s*$/ + hash[:description] = desc.sub(/\s*$/, '') + end - if hash[:protocols] - # The protocol can be a symbol, so... - if proto.is_a?(Symbol) - proto = [] + "" + end end - # Check to see if it already includes our proto - unless proto.include?(hash[:protocols]) - # We are missing their proto - proto += hash[:protocols] - base[:protocols] = proto + else + if line =~ /^\s+\d+/ and + Facter["operatingsystem"].value == "Darwin" + #Puppet.notice "Skipping wonky OS X port entry %s" % + # line.inspect + next end + Puppet.notice "Ignoring unparseable line '%s' in %s" % [line, self.target] + end + + if hash.empty? + return nil + else + return hash end + end - if hash.include?(:description) and ! base.include?(:description) - base[:description] = hash[:description] + # Merge two records into one. + def self.port_merge(one, two) + keys = [one.keys, two.keys].flatten.uniq + + # We'll be returning the 'one' hash. so make any necessary modifications + # to it. + keys.each do |key| + # The easy case + if one[key] == two[key] + next + elsif one[key] and ! two[key] + next + elsif ! one[key] and two[key] + one[key] = two[key] + elsif one[key].is_a?(Array) and two[key].is_a?(Array) + one[key] = [one[key], two[key]].flatten.uniq + else + # Keep the info from the first hash, so don't do anything + #Puppet.notice "Cannot merge %s in %s with %s" % + # [key, one.inspect, two.inspect] + end end - return true + return one end # Convert the current object into one or more services entry. - def self.to_record(hash) + def self.to_line(hash) + unless hash[:record_type] == :parsed + return super + end + + # Strangely, most sites seem to use tabs as separators. hash[:protocols].collect { |proto| - str = "%s\t%s/%s" % [hash[:name], hash[:number], proto] + str = "%s\t\t%s/%s" % [hash[:name], hash[:number], proto] if value = hash[:alias] and value != :absent - str += "\t%s" % value.join(" ") - else - str += "\t" + str += "\t\t%s" % value.join(" ") end if value = hash[:description] and value != :absent str += "\t# %s" % value - else - str += "\t" end str }.join("\n") |
