summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/port
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-11-13 02:07:07 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-11-13 02:07:07 +0000
commitbb80c1bb2c977fe462fa9d74031929547c2bbc40 (patch)
tree5774dab49b96db6cfb59c7316563a527612f495d /lib/puppet/provider/port
parent25b575fcdd588a619a89ac3fce474f4f35de3fb1 (diff)
downloadpuppet-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-xlib/puppet/provider/port/parsed.rb242
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")