summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-09-05 01:51:23 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-09-05 01:51:23 +0000
commit617fe58626aa8a13af10071ca87f66d6363cf058 (patch)
treedb9974c675c3b73cae56a253386f716e83bc8b6f /lib/puppet
parent8f39318ce46148c3bd483d790c965f277a4eb1c9 (diff)
downloadpuppet-617fe58626aa8a13af10071ca87f66d6363cf058.tar.gz
puppet-617fe58626aa8a13af10071ca87f66d6363cf058.tar.xz
puppet-617fe58626aa8a13af10071ca87f66d6363cf058.zip
Removing all of the changes I made towards refactoring in the last couple of days. They have all been moved into the sync-retrieve-refactor branch. This branch will soon become 0.19.0, and will not include that refactoring.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1555 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/provider.rb7
-rwxr-xr-xlib/puppet/provider/cron/parsed.rb161
-rw-r--r--lib/puppet/provider/host/parsed.rb78
-rwxr-xr-xlib/puppet/provider/mount/parsed.rb171
-rw-r--r--lib/puppet/provider/package/portage.rb124
-rwxr-xr-xlib/puppet/provider/parsedfile.rb174
-rwxr-xr-xlib/puppet/provider/port/parsed.rb139
-rwxr-xr-xlib/puppet/provider/sshkey/parsed.rb56
-rwxr-xr-xlib/puppet/server/fileserver.rb6
-rw-r--r--lib/puppet/statechange.rb138
-rw-r--r--lib/puppet/transaction.rb17
-rw-r--r--lib/puppet/type.rb115
-rwxr-xr-xlib/puppet/type/cron.rb9
-rwxr-xr-xlib/puppet/type/exec.rb23
-rwxr-xr-xlib/puppet/type/group.rb49
-rwxr-xr-xlib/puppet/type/mount.rb117
-rw-r--r--lib/puppet/type/package.rb3
-rwxr-xr-xlib/puppet/type/parsedtype.rb475
-rwxr-xr-xlib/puppet/type/parsedtype/host.rb (renamed from lib/puppet/type/host.rb)80
-rwxr-xr-xlib/puppet/type/parsedtype/mount.rb271
-rwxr-xr-xlib/puppet/type/parsedtype/port.rb261
-rwxr-xr-xlib/puppet/type/parsedtype/sshkey.rb123
-rw-r--r--lib/puppet/type/pfile.rb32
-rwxr-xr-xlib/puppet/type/pfile/checksum.rb8
-rwxr-xr-xlib/puppet/type/pfile/content.rb20
-rwxr-xr-xlib/puppet/type/pfile/ensure.rb40
-rwxr-xr-xlib/puppet/type/pfile/group.rb17
-rwxr-xr-xlib/puppet/type/pfile/mode.rb12
-rwxr-xr-xlib/puppet/type/pfile/source.rb28
-rw-r--r--lib/puppet/type/pfile/target.rb10
-rwxr-xr-xlib/puppet/type/pfile/type.rb11
-rwxr-xr-xlib/puppet/type/pfile/uid.rb27
-rwxr-xr-xlib/puppet/type/port.rb110
-rwxr-xr-xlib/puppet/type/sshkey.rb58
-rw-r--r--lib/puppet/type/state.rb94
-rwxr-xr-xlib/puppet/type/user.rb77
-rw-r--r--lib/puppet/util.rb9
37 files changed, 1372 insertions, 1778 deletions
diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb
index 04169e6e1..f51ea4450 100644
--- a/lib/puppet/provider.rb
+++ b/lib/puppet/provider.rb
@@ -139,7 +139,9 @@ class Puppet::Provider
return true
end
+ # Remove the reference to the model, so GC can clean up.
def clear
+ @model = nil
end
# Retrieve a named command.
@@ -155,11 +157,6 @@ class Puppet::Provider
@model.name
end
- # Remove the reference to the model, so GC can clean up.
- def remove
- @model = nil
- end
-
def to_s
"%s(provider=%s)" % [@model.to_s, self.class.name]
end
diff --git a/lib/puppet/provider/cron/parsed.rb b/lib/puppet/provider/cron/parsed.rb
deleted file mode 100755
index 1626162bd..000000000
--- a/lib/puppet/provider/cron/parsed.rb
+++ /dev/null
@@ -1,161 +0,0 @@
-require 'puppet/provider/parsedfile'
-
-Puppet::Type.type(:cron).provide :parsed, :parent => Puppet::Provider::ParsedFile do
- @fields = [:minute, :hour, :monthday, :month, :weekday, :command]
-
- # XXX This should be switched to use providers or something similar on
- # the backend.
- def self.defaulttype
- case Facter["operatingsystem"].value
- when "Solaris":
- return Puppet::FileType.filetype(:suntab)
- else
- return Puppet::FileType.filetype(:crontab)
- end
- end
-
- self.filetype = self.defaulttype()
-
- # We have to maintain separate file objects for every user, unfortunately.
- def self.filetype(user)
- @tabs ||= {}
- @tabs[user] ||= @filetype.new(user)
-
- @tabs[user]
- end
-
- # Parse a user's cron job into individual cron objects.
- #
- # Autogenerates names for any jobs that don't already have one; these
- # names will get written back to the file.
- #
- # This method also stores existing comments, and it stores all cron
- # jobs in order, mostly so that comments are retained in the order
- # they were written and in proximity to the same jobs.
- def self.parse(user, text)
- count = 0
-
- envs = []
- instances = []
- text.chomp.split("\n").each { |line|
- hash = {}
- case line
- when /^# Puppet Name: (.+)$/
- hash[:name] = $1
- next
- when /^#/:
- # add other comments to the list as they are
- instances << line
- next
- when /^\s*(\w+)\s*=\s*(.+)\s*$/:
- # Match env settings.
- if hash[:name]
- envs << line
- else
- instances << line
- end
- next
- when /^@(\w+)\s+(.+)/ # FreeBSD special cron crap
- fields().each do |field|
- next if field == :command
- hash[field] = :absent
- end
- hash[:special] = $1
- hash[:command] = $2
- else
- if match = /^(\S+) (\S+) (\S+) (\S+) (\S+) (.+)$/.match(line)
- fields().zip(match.captures).each { |param, value|
- if value == "*"
- hash[param] = [:absent]
- else
- if param == :command
- hash[param] = [value]
- else
- # We always want the 'is' value to be an
- # array
- hash[param] = value.split(",")
- end
- end
- }
- else
- # Don't fail on unmatched lines, just warn on them
- # and skip them.
- Puppet.warning "Could not match '%s'" % line
- next
- end
- end
-
- unless envs.empty?
- hash[:environment] = envs
- end
-
- hash[:user] = user
-
- instances << hash
-
- envs.clear
- count += 1
- }
-
- return instances
- end
-
- def self.retrieve(user)
- text = fileobj(user).read
- if text.nil? or text == ""
- return []
- else
- self.parse(user, text)
- end
- end
-
- # Another override. This will pretty much only ever have one user's instances,
- def self.store(instances)
- instances.find_all { |i| i.is_a? Hash }.collect { |i| i[:user] }.each do |user|
- fileobj(user).write(self.to_file(instances))
- end
- end
-
- # Convert the current object a cron-style string. Adds the cron name
- # as a comment above the cron job, in the form '# Puppet Name: <name>'.
- def self.to_record(hash)
- hash = {}
-
- str = ""
-
- str = "# Puppet Name: %s\n" % hash[:name]
-
- if @states.include?(:environment) and
- @states[:environment].should != :absent
- envs = @states[:environment].should
- unless envs.is_a? Array
- envs = [envs]
- end
-
- envs.each do |line| str += (line + "\n") end
- end
-
- line = nil
- if special = hash[:special]
- line = str + "@%s %s" %
- [special, hash[:command]]
- else
- line = str + self.class.fields.collect { |f|
- if hash[f] and hash[f] != :absent
- hash[f]
- else
- "*"
- end
- }.join(" ")
- end
-
- return line
- end
-
- # Override the mechanism for retrieving instances, because we're user-specific.
- def allinstances
- self.class.retrieve(@model[:user])
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb
deleted file mode 100644
index c606562a2..000000000
--- a/lib/puppet/provider/host/parsed.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-require 'puppet/provider/parsedfile'
-
-Puppet::Type.type(:host).provide :parsed, :parent => Puppet::Provider::ParsedFile do
- @path = "/etc/hosts"
- @filetype = Puppet::FileType.filetype(:flat)
-
- confine :exists => @path
-
- # Parse a host file
- #
- # This method also stores existing comments, and it stores all host
- # jobs in order, mostly so that comments are retained in the order
- # they were written and in proximity to the same jobs.
- def self.parse(text)
- count = 0
- instances = []
- 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+(\S+)\s*/, '')
- hash[:ip] = $1
- hash[:name] = $2
-
- unless line == ""
- line.sub!(/\s*/, '')
- line.sub!(/^([^#]+)\s*/) do |value|
- aliases = $1
- unless aliases =~ /^\s*$/
- hash[:alias] = aliases.split(/\s+/)
- end
-
- ""
- end
- end
- else
- raise Puppet::Error, "Could not match '%s'" % line
- end
-
- if hash[:alias] == ""
- hash.delete(:alias)
- end
-
- instances << hash
-
- count += 1
- end
- }
-
- return instances
- end
-
- # Convert the current object into a host-style string.
- def self.to_record(hash)
- [:ip, :name].each do |n|
- unless hash.has_key? n
- raise ArgumentError, "%s is a required attribute for hosts" % n
- end
- end
-
- str = "%s\t%s" % [hash[:ip], hash[:name]]
-
- if hash.include? :alias
- if hash[:alias].is_a? Array
- str += "\t%s" % hash[:alias].join("\t")
- else
- raise ArgumentError, "Aliases must be specified as an array"
- end
- end
-
- str
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/mount/parsed.rb b/lib/puppet/provider/mount/parsed.rb
deleted file mode 100755
index b768d6c5e..000000000
--- a/lib/puppet/provider/mount/parsed.rb
+++ /dev/null
@@ -1,171 +0,0 @@
-require 'puppet/provider/parsedfile'
-
-Puppet::Type.type(:mount).provide :parsed, :parent => Puppet::Provider::ParsedFile do
- @filetype = Puppet::FileType.filetype(:flat)
-
- commands :mount => "mount", :umount => "umount", :df => "df"
-
- def self.init
- @platform = Facter["operatingsystem"].value
- case @platform
- when "Solaris":
- @path = "/etc/vfstab"
- @fields = [:device, :blockdevice, :path, :fstype, :pass, :atboot,
- :options]
- @defaults = [ nil ] * @fields.size
- when "Darwin":
- @filetype = Puppet::FileType.filetype(:netinfo)
- @filetype.format = "fstab"
- @path = "mounts"
- @fields = [:device, :path, :fstype, :options, :dump, :pass]
- @defaults = [ nil ] * @fields.size
-
- # How to map the dumped table to what we want
- @fieldnames = {
- "name" => :device,
- "dir" => :path,
- "dump_freq" => :dump,
- "passno" => :pass,
- "vfstype" => :fstype,
- "opts" => :options
- }
- else
- @path = "/etc/fstab"
- @fields = [:device, :path, :fstype, :options, :dump, :pass]
- @defaults = [ nil ] * 4 + [ "0", "2" ]
- end
-
- # Allow Darwin to override the default filetype
- unless defined? @filetype
- @filetype = Puppet::FileType.filetype(:flat)
- end
- end
-
- init
-
- confine :exists => @path
-
- def self.clear
- init
- super
- end
-
- # Parse a mount tab.
- #
- # This method also stores existing comments, and it stores all
- # mounts in order, mostly so that comments are retained in the
- # order they were written and in proximity to the same fses.
- def self.parse(text)
- # provide a single exception for darwin & netinfo
- if @filetype == Puppet::FileType.filetype(:netinfo)
- return parseninfo(text)
- end
- count = 0
-
- instances = []
- text.chomp.split("\n").each { |line|
- hash = {}
- case line
- when /^#/, /^\s*$/:
- # add comments and blank lines to the list as they are
- instances << line
- comment(line)
- else
- values = line.split(/\s+/)
- if @fields.length < values.length
- raise Puppet::Error, "Could not parse line %s" % line
- end
-
- values = @defaults.zip(values).collect { |d, v| v || d }
- unless @fields.length == values.length
- raise Puppet::Error, "Could not parse line %s" % line
- end
-
- @fields.zip(values).each do |field, value|
- hash[field] = value
- end
-
- instances << hash
- count += 1
- end
- }
-
- return instances
- end
-
- # Parse a netinfo table.
- def self.parseninfo(text)
- array = @fileobj.to_array(text)
-
- instances = []
- array.each do |record|
- hash = {}
- @fieldnames.each do |name, field|
- if value = record[name]
- if field == :options
- hash[field] = value.join(",")
- else
- hash[field] = value[0]
- end
- else
- raise ArgumentError, "Field %s was not provided" % [name]
- end
- end
-
- instances << hash
- end
-
- return instances
- end
-
- # Convert the current object into an fstab-style string.
- def self.to_record(hash)
- self.fields.collect do |field|
- if value = hash[field]
- value
- else
- raise Puppet::Error,
- "Could not retrieve value for %s" % field
- end
- end.join("\t")
- end
-
- # This only works when the mount point is synced to the fstab.
- def mount
- output = %x{#{command(:mount)} #{@model[:path]} 2>&1}
-
- unless $? == 0
- raise Puppet::Error, "Could not mount %s: %s" % [@model[:path], output]
- end
- end
-
- # This only works when the mount point is synced to the fstab.
- def unmount
- output = %x{#{command(:umount)} #{@model[:path]}}
-
- unless $? == 0
- raise Puppet::Error, "Could not unmount %s" % @model[:path]
- end
- end
-
- # Is the mount currently mounted?
- def mounted?
- platform = Facter["operatingsystem"].value
- df = command(:df)
- case Facter["operatingsystem"].value
- # Solaris's df prints in a very weird format
- when "Solaris": df = "#{command(:df)} -k"
- end
- %x{#{df}}.split("\n").find do |line|
- fs = line.split(/\s+/)[-1]
- if platform == "Darwin"
- fs == "/private/var/automount" + @model[:path] or
- fs == @model[:path]
- else
- fs == @model[:path]
- end
- end
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb
deleted file mode 100644
index 873f63f68..000000000
--- a/lib/puppet/provider/package/portage.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-Puppet::Type.type(:package).provide :portage do
- desc "Provides packaging support for Gentoo's portage system."
-
- commands :emerge => "emerge", :eix => "eix"
-
- defaultfor :operatingsystem => :gentoo
-
- def self.list
- search_format = /(\S+) (\S+) \[(.*)\] \[(\S*)\] ([\S]*) (.*)/
- result_fields = [:category, :name, :version, :version_available,
- :vendor, :description]
- command = "#{command(:eix)} --format \"{<installedversions>}<category> <name> [<installedversions>] [<best>] <homepage> <description>{}\""
-
- begin
- search_output = execute( command )
-
- packages = []
- search_output.each do |search_result|
- match = search_format.match( search_result )
-
- if( match )
- package = {:ensure => :present}
- result_fields.zip( match.captures ) { |field, value| package[field] = value }
- if self.is_a? Puppet::Type and type = @model[:type]
- package[:type] = type
- elsif self.is_a? Module and self.respond_to? :name
- package[:type] = self.name
- else
- raise Puppet::DevError, "Cannot determine package type"
- end
- if package[:version]
- package[:version] = package[:version].split.last
- end
-
- packages.push( Puppet.type(:package).installedpkg(package) )
- end
- end
-
- return packages
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
- end
- end
-
- def install
- if @model[:version]
- # We must install a specific version
- package_name = "=#{@model[:name]}-#{@model[:version]}"
- else
- package_name = @model[:name]
- end
- command = "EMERGE_DEFAULT_OPTS=\"\" #{command(:emerge)} #{package_name}"
- begin
- output = execute( command )
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
- end
- end
-
- def uninstall
- if @model[:version]
- # We must uninstall a specific version
- package_name = "=#{@model[:name]}-#{@model[:version]}"
- else
- package_name = @model[:name]
- end
- command ="EMERGE_DEFAULT_OPTS=\"\" #{command(:emerge)} --unmerge #{package_name}"
- begin
- output = execute( command )
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
- end
- end
-
- def update
- self.install
- end
-
- def query
- search_format = /(\S+) (\S+) \[(.*)\] \[(\S*)\] ([\S]*) (.*)/
- result_fields = [:category, :name, :version, :version_available, :vendor, :description]
-
- search_field = @model[:name].include?( '/' ) ? "--category-name" : "--name"
- command = "#{command(:eix)} --format \"<category> <name> [<installedversions>] [<best>] <homepage> <description>\" --exact #{search_field} #{@model[:name]}"
-
- begin
- search_output = execute( command )
-
- packages = []
- search_output.each do |search_result|
- match = search_format.match( search_result )
-
- if( match )
- package = {}
- result_fields.zip( match.captures ) { |field, value| package[field] = value unless value.empty? }
- package[:ensure] = package[:version] ? :present : :absent
- package[:version] = package[:version].split.last if package[:version]
- packages << package
- end
- end
-
- case packages.size
- when 0
- return nil
- when 1
- return packages[0]
- else
- self.fail "More than one package with the specified name [#{@model[:name]}], please use category/name to disambiguate"
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
- end
- end
-
- def latest
- return self.query[:version_available]
- end
-
- def versionable?
- true
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb
deleted file mode 100755
index f690c03a4..000000000
--- a/lib/puppet/provider/parsedfile.rb
+++ /dev/null
@@ -1,174 +0,0 @@
-require 'puppet'
-
-class Puppet::Provider::ParsedFile < Puppet::Provider
- class << self
- attr_accessor :filetype, :fields
- attr_reader :path
- attr_writer :fileobj
- end
-
- # Override 'newstate' so that all states default to having the
- # correct parent type
- def self.newstate(name, options = {}, &block)
- options[:parent] ||= Puppet::State::ParsedParam
- super(name, options, &block)
- end
-
- # Add another type var.
- def self.initvars
- @instances = []
- super
- end
-
- # Add a non-object comment or whatever to our list of instances
- def self.comment(line)
- @instances << line
- end
-
- # Override the default Puppet::Type method, because instances
- # also need to be deleted from the @instances hash
- def self.delete(child)
- if @instances.include?(child)
- @instances.delete(child)
- end
- super
- end
-
- # Initialize the object if necessary.
- def self.fileobj
- @fileobj ||= @filetype.new(@path)
-
- @fileobj
- end
-
- # Return the header placed at the top of each generated file, warning
- # users that modifying this file manually is probably a bad idea.
- def self.header
-%{# HEADER: This file was autogenerated at #{Time.now}
-# HEADER: by puppet. While it can still be managed manually, it
-# HEADER: is definitely not recommended.\n}
- end
-
- # Parse a file
- #
- # Subclasses must override this method.
- def self.parse(text)
- raise Puppet::DevError, "Parse was not overridden in %s" %
- self.name
- end
-
- # If they change the path, we need to get rid of our cache object
- def self.path=(path)
- @fileobj = nil
- @path = path
- end
-
- # Retrieve the text for the file. Returns nil in the unlikely
- # event that it doesn't exist.
- def self.retrieve
- text = fileobj.read
- if text.nil? or text == ""
- # there is no file
- return []
- else
- self.parse(text)
- end
- end
-
- # Write out the file.
- def self.store(instances)
- if instances.empty?
- Puppet.notice "No %s instances for %s" % [self.name, @path]
- else
- fileobj.write(self.to_file(instances))
- end
- end
-
- # Collect all Host instances convert them into literal text.
- def self.to_file(instances)
- str = self.header()
- unless instances.empty?
- # Reject empty hashes and those with :ensure == :absent
- str += instances.reject { |obj|
- obj.is_a? Hash and (obj.empty? or obj[:ensure] == :absent)
- }.collect { |obj|
- # If it's a hash, convert it, otherwise just write it out
- if obj.is_a?(Hash)
- to_record(obj)
- else
- obj.to_s
- end
- }.join("\n") + "\n"
-
- return str
- else
- Puppet.notice "No %s instances" % self.name
- return ""
- end
- end
-
- # A Simple wrapper method that subclasses can override, so there's more control
- # over how instances are retrieved.
- def allinstances
- self.class.retrieve
- end
-
- def clear
- super
- @instances = nil
- end
-
- # Return a hash that maps to our info, if possible.
- def hash
- @instances = allinstances()
-
- if @instances and h = @instances.find do |o|
- o.is_a? Hash and o[:name] == @model[:name]
- end
- @me = h
- else
- @me = {}
- if @instances.empty?
- @instances = [@me]
- else
- @instances << @me
- end
- end
-
- return @me
- end
-
- def initialize(model)
- super
-
- @instances = nil
- end
-
- def store(hash = nil)
- hash ||= self.model.to_hash
-
- unless @instances
- self.hash
- end
-
- if hash.empty?
- @me.clear
- else
- hash.each do |name, value|
- if @me[name] != hash[name]
- @me[name] = hash[name]
- end
- end
-
- @me.each do |name, value|
- unless hash.has_key? name
- @me.delete(name)
- end
- end
- end
-
- self.class.store(@instances)
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/port/parsed.rb b/lib/puppet/provider/port/parsed.rb
deleted file mode 100755
index d65a0777f..000000000
--- a/lib/puppet/provider/port/parsed.rb
+++ /dev/null
@@ -1,139 +0,0 @@
-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
-
- instances << hash
- namehash[hash[:name]] = hash
-
- count += 1
- end
- }
-
- return instances
- end
-
- def self.portmerge(base, hash)
- unless base.has_key?(:protocols)
- return false
- end
-
- # This method is only called from parsing, so we only worry
- # about 'is' values.
- proto = base[:protocols]
-
- if proto.nil? or proto == :absent
- # We are an unitialized object; we've got 'should'
- # values but no 'is' values
- return false
- end
-
- # If this is happening, our object exists
- base[:ensure] = :present
-
- if hash[:protocols]
- # The protocol can be a symbol, so...
- if proto.is_a?(Symbol)
- proto = []
- 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
- end
- end
-
- if hash.include?(:description) and ! base.include?(:description)
- base[:description] = hash[:description]
- end
-
- return true
- end
-
- # Convert the current object into one or more services entry.
- def self.to_record(hash)
- hash[:protocols].collect { |proto|
- str = "%s\t%s/%s" % [hash[:name], hash[:number], proto]
-
- if value = hash[:alias] and value != :absent
- str += "\t%s" % value.join(" ")
- else
- str += "\t"
- end
-
- if value = hash[:description] and value != :absent
- str += "\t# %s" % value
- else
- str += "\t"
- end
- str
- }.join("\n")
- end
-end
-
-# $Id$
diff --git a/lib/puppet/provider/sshkey/parsed.rb b/lib/puppet/provider/sshkey/parsed.rb
deleted file mode 100755
index e1dbeaad6..000000000
--- a/lib/puppet/provider/sshkey/parsed.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'puppet/provider/parsedfile'
-
-Puppet::Type.type(:sshkey).provide :parsed, :parent => Puppet::Provider::ParsedFile do
- @filetype = Puppet::FileType.filetype(:flat)
- @path = "/etc/ssh/ssh_known_hosts"
- @fields = [:name, :type, :key]
-
- # Parse an sshknownhosts file
- #
- # This method also stores existing comments, and it stores all host
- # jobs in order, mostly so that comments are retained in the order
- # they were written and in proximity to the same jobs.
- def self.parse(text)
- count = 0
- instances = []
- 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
- hash = {}
- fields().zip(line.split(" ")).each { |param, value|
- hash[param] = value
- }
-
- if hash[:name] =~ /,/
- names = hash[:name].split(",")
- hash[:name] = names.shift
- hash[:alias] = names
- end
-
- if hash[:alias] == ""
- hash.delete(:alias)
- end
-
- instances << hash
- count += 1
- end
- }
-
- return instances
- end
-
- # Convert the current object into an entry for a known-hosts file.
- def self.to_record(hash)
- name = hash[:name]
- if hash.include?(:alias)
- name += "," + hash[:alias].join(",")
- end
- [name, hash[:type], hash[:key]].join(" ")
- end
-end
-
-# $Id$
diff --git a/lib/puppet/server/fileserver.rb b/lib/puppet/server/fileserver.rb
index 93f3310d1..49af26c54 100755
--- a/lib/puppet/server/fileserver.rb
+++ b/lib/puppet/server/fileserver.rb
@@ -63,7 +63,11 @@ class Server
desc = []
CHECKPARAMS.each { |check|
if state = obj.state(check)
- desc << state.retrieve
+ unless state.is
+ mount.debug "Manually retrieving info for %s" % check
+ state.retrieve
+ end
+ desc << state.is
else
if check == "checksum" and obj.state(:type).is == "file"
mount.notice "File %s does not have data for %s" %
diff --git a/lib/puppet/statechange.rb b/lib/puppet/statechange.rb
index d11a985fe..4884026fe 100644
--- a/lib/puppet/statechange.rb
+++ b/lib/puppet/statechange.rb
@@ -11,55 +11,19 @@ module Puppet
# The log file generated when this object was changed.
attr_reader :report
- # Switch the goals of the state, thus running the change in reverse.
- def backward
- @state.should = @is
- @should = @is
- @is = @state.retrieve
- @state.is = @is
-
- unless defined? @transaction
- raise Puppet::Error,
- "StateChange '%s' tried to be executed outside of transaction" %
- self
- end
- unless @state.insync?
- @state.info "Backing %s" % self
- return self.go
- else
- @state.debug "rollback is already in sync: %s vs. %s" %
- [@state.is.inspect, @state.should.inspect]
- return nil
- end
- end
-
- def forward
- #@state.debug "moving change forward"
+ def initialize(state)
+ @state = state
+ @path = [state.path,"change"].flatten
+ @is = state.is
- unless defined? @transaction
- raise Puppet::Error,
- "StateChange '%s' tried to be executed outside of transaction" %
- self
+ if state.insync?
+ raise Puppet::Error.new(
+ "Tried to create a change for in-sync state %s" % state.name
+ )
end
+ @should = state.should
- return self.go
- end
-
- # Generate an appropriate event from the is/should values.
- def genevent
- tail = if @state.name == :ensure
- if @should == :present
- "created"
- elsif @should == :absent
- "deleted"
- else
- @should.to_s
- end
- else
- "changed"
- end
-
- [state.parent.class.name.to_s, tail].join("_").intern
+ @changed = false
end
# Perform the actual change. This method can go either forward or
@@ -81,39 +45,28 @@ module Puppet
# [@state.is.inspect, @state.should.inspect]
# The transaction catches any exceptions here.
- if @state.method(:sync).arity == 0
- @state.warnstamp :syncwoutvalue, "sync() should accept a value"
- events = @state.sync
- else
- events = @state.sync(@should)
+ events = @state.sync
+ if events.nil?
+ return nil
end
- unless events.is_a? Array
+ if events.is_a?(Array)
+ if events.empty?
+ return nil
+ end
+ else
events = [events]
end
+
+ return events.collect { |event|
+ # default to a simple event type
+ if ! event.is_a?(Symbol)
+ @state.warning("State '%s' returned invalid event '%s'; resetting to default" %
+ [@state.class,event])
- events = events.collect do |e|
- if e.nil?
- genevent()
- else
- if ! e.is_a?(Symbol)
- @state.warning(
- "State '%s' returned invalid event '%s'; resetting" %
- [@state.class,e]
- )
- genevent()
- else
- e
- end
+ event = @state.parent.class.name.id2name + "_changed"
end
- end.reject { |e| e == :nochange }
-
- if events.empty?
- return nil
- end
-
- return events.collect { |event|
# i should maybe include object type, but the event type
# should basically point to that, right?
#:state => @state,
@@ -129,25 +82,36 @@ module Puppet
}
end
- def initialize(state, is = nil)
- @state = state
- @path = [state.path,"change"].flatten
+ def forward
+ #@state.debug "moving change forward"
- if is
- @is = is
- else
- state.warning "did not pass 'is' to statechange"
- @is = state.is
+ unless defined? @transaction
+ raise Puppet::Error,
+ "StateChange '%s' tried to be executed outside of transaction" %
+ self
end
- if state.insync?
- raise Puppet::Error.new(
- "Tried to create a change for in-sync state %s" % state.name
- )
- end
- @should = state.should
+ return self.go
+ end
- @changed = false
+ # Switch the goals of the state, thus running the change in reverse.
+ def backward
+ @state.should = @is
+ @state.retrieve
+
+ unless defined? @transaction
+ raise Puppet::Error,
+ "StateChange '%s' tried to be executed outside of transaction" %
+ self
+ end
+ unless @state.insync?
+ @state.info "Backing %s" % self
+ return self.go
+ else
+ @state.debug "rollback is already in sync: %s vs. %s" %
+ [@state.is.inspect, @state.should.inspect]
+ return nil
+ end
end
def noop
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index d947afbf2..899aaa456 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -90,7 +90,7 @@ class Transaction
# Mark that our change happened, so it can be reversed
# if we ever get to that point
- unless events.nil?
+ unless events.nil? or (events.is_a?(Array) and events.empty?)
change.changed = true
@objectmetrics[:applied] += 1
end
@@ -98,15 +98,6 @@ class Transaction
events
}.flatten.reject { |e| e.nil? }
- # If our child responds to a 'flush' method, call it.
- if childevents.length > 0 and child.respond_to? :flush
- begin
- child.flush
- rescue => detail
- raise Puppet::Error, "Could not flush: %s" % detail, detail.backtrace
- end
- end
-
unless changes.empty?
# Record when we last synced
child.cache(:synced, Time.now)
@@ -205,9 +196,6 @@ class Transaction
[self.object_id, @count]
allevents
- ensure
- # Unset 'is' everywhere. This is relatively hackish, but, eh.
- @objects.each do |o| o.clear end
end
# Determine whether a given object has failed.
@@ -329,9 +317,6 @@ class Transaction
# And return the events for collection
events
}.flatten.reject { |e| e.nil? }
- ensure
- # Unset 'is' everywhere. This is relatively hackish, but, eh.
- @objects.each do |o| o.clear end
end
# Trigger any subscriptions to a child. This does an upwardly recursive
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 53712d365..d87cbcbd3 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -29,10 +29,13 @@ class Type < Puppet::Element
attr_accessor :file, :line
attr_reader :tags, :parent
- attr_accessor :implicit
- attr_writer :title
+ attr_writer :implicit, :title
def implicit?
- self.implicit
+ if defined? @implicit and @implicit
+ return true
+ else
+ return false
+ end
end
include Enumerable
@@ -53,7 +56,10 @@ class Type < Puppet::Element
# iterate across all of the subclasses of Type
def self.eachtype
@types.each do |name, type|
- yield type
+ # Only consider types that have names
+ #if ! type.parameters.empty? or ! type.validstates.empty?
+ yield type
+ #end
end
end
@@ -301,7 +307,6 @@ class Type < Puppet::Element
def self.clear
if defined? @objects
@objects.each do |name, obj|
- obj.clear
obj.remove(true)
end
@objects.clear
@@ -938,10 +943,8 @@ class Type < Puppet::Element
end
end
- # Remove a state from the object; useful in testing or in cleanup
- # when an error has been encountered. Removes all objects with a given name,
- # not just states. Some classes have both an alias state and an alias
- # metaparam.
+ # remove a state from the object; useful in testing or in cleanup
+ # when an error has been encountered
def delete(attr)
case attr
when Puppet::Type
@@ -949,20 +952,13 @@ class Type < Puppet::Element
@children.delete(attr)
end
else
- done = false
if @states.has_key?(attr)
@states.delete(attr)
- done = true
- end
- if @parameters.has_key?(attr)
+ elsif @parameters.has_key?(attr)
@parameters.delete(attr)
- done = true
- end
- if @metaparams.has_key?(attr)
+ elsif @metaparams.has_key?(attr)
@metaparams.delete(attr)
- done = true
- end
- unless done
+ else
raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
end
end
@@ -1269,7 +1265,7 @@ class Type < Puppet::Element
# Remove the reference to the provider.
if self.provider
- @provider.remove
+ @provider.clear
@provider = nil
end
end
@@ -1711,19 +1707,6 @@ class Type < Puppet::Element
#@cache[name] = value
end
- # Remove any vestages of the transaction we're in. This is currently the only
- # way to know if you're within a transaction -- if '@is' is set, yes, else,
- # no.
- def clear
- @states.each do |name, state|
- state.is = nil
- end
-
- if provider and provider.respond_to? :clear
- provider.clear
- end
- end
-
# Look up the schedule and set it appropriately. This is done after
# the instantiation phase, so that the schedule can be anywhere in the
# file.
@@ -1964,25 +1947,9 @@ class Type < Puppet::Element
def retrieve
# it's important to use the method here, as it follows the order
# in which they're defined in the object
- is = {}
states().each { |state|
- is[state.name] = state.retrieve
+ state.retrieve
}
-
- is
- end
-
- # Convert our object to a hash. This just includes states.
- def to_hash
- rethash = {}
-
- [@parameters, @metaparams, @states].each do |hash|
- hash.each do |name, obj|
- rethash[name] = obj.value
- end
- end
-
- rethash
end
# convert to a string
@@ -2033,22 +2000,30 @@ class Type < Puppet::Element
end
# Retrieve the changes associated with all of the states.
- def statechanges(is)
+ def statechanges
# If we are changing the existence of the object, then none of
# the other states matter.
changes = []
-
if @states.include?(:ensure) and ! @states[:ensure].insync?
- changes = [Puppet::StateChange.new(@states[:ensure], is[:ensure])]
+ #self.info "ensuring %s from %s" %
+ # [@states[:ensure].should, @states[:ensure].is]
+ changes = [Puppet::StateChange.new(@states[:ensure])]
# Else, if the 'ensure' state is correctly absent, then do
# nothing
- elsif @states.include?(:ensure) and is[:ensure] == :absent
+ elsif @states.include?(:ensure) and @states[:ensure].is == :absent
+ #self.info "Object is correctly absent"
return []
else
+ #if @states.include?(:ensure)
+ # self.info "ensure: Is: %s, Should: %s" %
+ # [@states[:ensure].is, @states[:ensure].should]
+ #else
+ # self.info "no ensure state"
+ #end
changes = states().find_all { |state|
! state.insync?
}.collect { |state|
- Puppet::StateChange.new(state, is[state.name])
+ Puppet::StateChange.new(state)
}
end
@@ -2084,35 +2059,11 @@ class Type < Puppet::Element
# it's important that we call retrieve() on the type instance,
# not directly on the state, because it allows the type to override
# the method, like pfile does
- is = self.retrieve
-
- unless is.is_a? Hash
- warnstamp :nohashreturned, "'retrieve' did not return hash"
- is = {}
- end
-
- @@novalreturned ||= {}
- states.each do |state|
- unless is.include? state.name
- warnstamp "no#{state.name}returned",
- "did not get %s from retrieve" % state.name
- is[state.name] = state.is
- end
- end
-
- # For now, set the 'is' values
- is.each do |name, value|
- # A special value to indicate we shouldn't do anything here; usually
- # the result of an internal error.
- next if value == :unmanaged
- if @states.include? name
- @states[name].is = value
- end
- end
+ self.retrieve
# states() is a private method, returning an ordered list
unless self.class.depthfirst?
- changes += statechanges(is)
+ changes += statechanges()
end
changes << @children.collect { |child|
@@ -2122,7 +2073,7 @@ class Type < Puppet::Element
}
if self.class.depthfirst?
- changes += statechanges(is)
+ changes += statechanges()
end
changes.flatten!
diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb
index a911dac04..03ac24d29 100755
--- a/lib/puppet/type/cron.rb
+++ b/lib/puppet/type/cron.rb
@@ -1,3 +1,7 @@
+require 'etc'
+require 'facter'
+require 'puppet/type/state'
+require 'puppet/filetype'
require 'puppet/type/parsedtype'
module Puppet
@@ -5,7 +9,7 @@ module Puppet
# as parameters, with the 'command' as the single state. Also requires a
# completely symbolic 'name' paremeter, which gets written to the file
# and is used to manage the job.
- newtype(:cron, Puppet::Type::ParsedType) do
+ newtype(:cron) do
# A base class for all of the Cron parameters, since they all have
# similar argument checking going on. We're stealing the base class
@@ -333,6 +337,9 @@ module Puppet
}
"
+ @instances = {}
+ @tabs = {}
+
class << self
attr_accessor :filetype
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 8ccebd242..0dc3ec02a 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -111,29 +111,19 @@ module Puppet
end
end
- def insync?
- case self.is
- when :failedchecks
- return true
- when :shouldrun
- return false
- else
- raise ArgumentError, "Invalid 'is' value '%s'" % self.is.inspect
- end
- end
-
- # Figure out whether we should run.
+ # First verify that all of our checks pass.
def retrieve
- # First make sure all of our checks pass.
+ # Default to somethinng
+
if @parent.check
- return :shouldrun
+ self.is = :notrun
else
- return :failedchecks
+ self.is = self.should
end
end
# Actually execute the command.
- def sync(value = nil)
+ def sync
olddir = nil
self.checkexe
@@ -454,7 +444,6 @@ module Puppet
val = [val] unless val.is_a? Array
val.each do |value|
unless @parameters[check].check(value)
- info "Failed '%s' check" % check
return false
end
end
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index c6e3324a7..b03f57907 100755
--- a/lib/puppet/type/group.rb
+++ b/lib/puppet/type/group.rb
@@ -26,12 +26,16 @@ module Puppet
newstate(:ensure) do
desc "The basic state that the object should be in."
- newvalue(:present, :event => :group_created) do
+ newvalue(:present) do
provider.create
+
+ :group_created
end
- newvalue(:absent, :event => :group_deleted) do
+ newvalue(:absent) do
provider.delete
+
+ :group_removed
end
# If they're talking about the thing at all, they generally want to
@@ -46,7 +50,7 @@ module Puppet
def change_to_s
begin
- if self.is == :absent
+ if @is == :absent
return "created"
elsif self.should == :absent
return "removed"
@@ -65,11 +69,30 @@ module Puppet
def retrieve
if provider.exists?
- return :present
+ @is = :present
else
- return :absent
+ @is = :absent
end
end
+
+ # The default 'sync' method only selects among a list of registered
+ # values.
+ def sync
+ if self.insync?
+ self.info "already in sync"
+ return nil
+ #else
+ #self.info "%s vs %s" % [self.is.inspect, self.should.inspect]
+ end
+ unless self.class.values
+ self.devfail "No values defined for %s" %
+ self.class.name
+ end
+
+ # Set ourselves to whatever our should value is.
+ self.set
+ end
+
end
newstate(:gid) do
@@ -100,17 +123,16 @@ module Puppet
end
def retrieve
- return provider.gid
+ @is = provider.gid
end
- def sync(value)
+ def sync
if self.should == :absent
raise Puppet::DevError, "GID cannot be deleted"
else
- provider.gid = value
+ provider.gid = self.should
+ :group_modified
end
-
- return nil
end
munge do |gid|
@@ -162,19 +184,18 @@ module Puppet
def retrieve
if @provider.exists?
- return super
+ super
else
# the group does not exist
#unless @states.include?(:gid)
# self[:gid] = :auto
#end
- current = {}
@states.each { |name, state|
- current[state.name] = :absent
+ state.is = :absent
}
- return current
+ return
end
end
end
diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb
deleted file mode 100755
index 641ff8592..000000000
--- a/lib/puppet/type/mount.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-require 'puppet/type/parsedtype'
-
-module Puppet
- newtype(:mount, Puppet::Type::ParsedType) do
- newstate(:ensure) do
- desc "Control what to do with this mount. If the value is
- ``present``, the mount is entered into the mount table,
- but not mounted, if it is ``absent``, the entry is removed
- from the mount table and the filesystem is unmounted if
- currently mounted, if it is ``mounted``, the filesystem
- is entered into the mount table and mounted."
-
- newvalue(:present, :event => :mount_created) do
- end
-
- newvalue(:absent, :event => :mount_deleted) do
- if provider.mounted?
- provider.unmount
- end
- end
-
- newvalue(:mounted, :event => :mount_mounted) do
- # We have to flush any changes to disk.
- @parent.flush
-
- provider.mount
- end
-
- defaultto do
- if @parent.managed?
- :mounted
- else
- nil
- end
- end
-
- def retrieve
- if provider.mounted?
- return :mounted
- else
- val = super()
- return val
- end
- end
-
- # The default method doesn't, um, do anything, since it's all
- # done in the flush at the end.
- #def sync(value)
- # set(value)
- #end
- end
-
- newstate(:device) do
- desc "The device providing the mount. This can be whatever
- device is supporting by the mount, including network
- devices or devices specified by UUID rather than device
- path, depending on the operating system."
- end
-
- # Solaris specifies two devices, not just one.
- newstate(:blockdevice) do
- desc "The the device to fsck. This is state is only valid
- on Solaris, and in most cases will default to the correct
- value."
-
- # Default to the device but with "dsk" replaced with "rdsk".
- defaultto do
- if Facter["operatingsystem"].value == "Solaris"
- device = @parent.value(:device)
- if device =~ %r{/dsk/}
- device.sub(%r{/dsk/}, "/rdsk/")
- else
- nil
- end
- else
- nil
- end
- end
- end
-
- newstate(:fstype) do
- desc "The mount type. Valid values depend on the
- operating system."
- end
-
- newstate(:options) do
- desc "Mount options for the mounts, as they would
- appear in the fstab."
- end
-
- newstate(:pass) do
- desc "The pass in which the mount is checked."
- end
-
- newstate(:atboot) do
- desc "Whether to mount the mount at boot. Not all platforms
- support this."
- end
-
- newstate(:dump) do
- desc "Whether to dump the mount. Not all platforms
- support this."
- end
-
- newparam(:path) do
- desc "The mount path for the mount."
-
- isnamevar
- end
-
- @doc = "Manages mounted mounts, including putting mount
- information into the mount table. The actual behavior depends
- on the value of the 'ensure' parameter."
- end
-end
-
-# $Id$
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index 3c4d20cc9..f7ae0f0d4 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -136,7 +136,8 @@ module Puppet
@is = @parent.retrieve
end
- def sync(value)
+ def sync
+ value = self.should
unless value.is_a?(Symbol)
value = value.intern
end
diff --git a/lib/puppet/type/parsedtype.rb b/lib/puppet/type/parsedtype.rb
index 9d37adf17..b0e5f618d 100755
--- a/lib/puppet/type/parsedtype.rb
+++ b/lib/puppet/type/parsedtype.rb
@@ -4,205 +4,352 @@ require 'puppet/filetype'
require 'puppet/type/state'
module Puppet
- # The base parameter for all of these types. Its only job is to copy
- # the 'should' value to the 'is' value and to do support the right logging
- # and such.
- class State::ParsedParam < Puppet::State
- # This is the info retrieved from disk.
- attr_accessor :found
-
- def self.isoptional
- @isoptional = true
- end
+ class State
+ # The base parameter for all of these types. Its only job is to copy
+ # the 'should' value to the 'is' value and to do support the right logging
+ # and such.
+ class ParsedParam < Puppet::State
+ def self.isoptional
+ @isoptional = true
+ end
- def self.isoptional?
- if defined? @isoptional
- return @isoptional
- else
- return false
+ def self.isoptional?
+ if defined? @isoptional
+ return @isoptional
+ else
+ return false
+ end
end
- end
- # By default, support ':absent' as a value for optional
- # parameters. Any parameters that define their own validation
- # need to do this manuallly.
- validate do |value|
- if self.class.isoptional? and (
- value == "absent" or value == :absent
- )
- return :absent
- else
- return value
+ # By default, support ':absent' as a value for optional
+ # parameters. Any parameters that define their own validation
+ # need to do this manuallly.
+ validate do |value|
+ if self.class.isoptional? and (
+ value == "absent" or value == :absent
+ )
+ return :absent
+ else
+ return value
+ end
end
- end
- def clear
- super
- @found = nil
- end
+ # Fix things so that the fields have to match exactly, instead
+ # of only kinda
+ def insync?
+ self.is == self.should
+ end
- # Fix things so that the fields have to match exactly, instead
- # of only kinda
- def insync?
- self.is == self.should
- end
+ # Normally this would retrieve the current value, but our state is not
+ # actually capable of doing so.
+ def retrieve
+ # If we've synced, then just copy the values over and return.
+ # This allows this state to behave like any other state.
+ if defined? @synced and @synced
+ # by default, we only copy over the first value.
+ @is = @synced
+ @synced = false
+ return
+ end
- # Normally this would retrieve the current value, but our state is not
- # actually capable of doing so. So, we retrieve the whole object and
- # just collect our current state. Note that this method is not called
- # during a transaction, since transactions call the parent object method.
- def retrieve
- @parent.retrieve[self.name]
- end
+ unless defined? @is and ! @is.nil?
+ @is = :absent
+ end
+ end
- # If the ensure state is out of sync, it will always be called
- # first, so I don't need to worry about that.
- def sync(value)
- # We only pass through to the parent method if there are values
- # defined. Otherwise, there's no work to do, since all of the
- # work is done in the flush.
- if self.class.values and ! self.class.values.empty?
- super(value)
- end
- # The value gets flushed later.
- return nil
- end
- end
+ # If the ensure state is out of sync, it will always be called
+ # first, so I don't need to worry about that.
+ def sync(nostore = false)
+ ebase = @parent.class.name.to_s
- # The collection of classes that are just simple records aggregated
- # into a file. See 'host.rb' for an example.
- class Type::ParsedType < Puppet::Type
- @name = :parsedtype
-
- # Convert the hash to an object.
- def self.hash2obj(hash)
- obj = nil
-
- namevar = self.namevar
- unless hash.include?(namevar) and hash[namevar]
- raise Puppet::DevError, "Hash was not passed with namevar"
- end
-
- # if the obj already exists with that name...
- if obj = self[hash[namevar]]
- # We're assuming here that objects with the same name
- # are the same object, which *should* be the case, assuming
- # we've set up our naming stuff correctly everywhere.
-
- # Mark found objects as present
- obj.is = [:ensure, :present]
- obj.state(:ensure).found = :present
- hash.each { |param, value|
- if state = obj.state(param)
- state.is = value
- elsif val = obj[param]
- obj[param] = val
- else
- # There is a value on disk, but it should go away
- obj.is = [param, value]
- obj[param] = :absent
+ tail = nil
+ if self.class.name == :ensure
+ # We're either creating or destroying the object
+ if @is == :absent
+ #@is = self.should
+ tail = "created"
+
+ # If we're creating it, then sync all of the other states
+ # but tell them not to store (we'll store just once,
+ # at the end).
+ unless nostore
+ @parent.eachstate { |state|
+ next if state == self or state.name == :ensure
+ state.sync(true)
+ }
+ end
+ elsif self.should == :absent
+ @parent.remove(true)
+ tail = "deleted"
end
- }
- else
- # create a new obj, since no existing one seems to
- # match
- obj = self.create(namevar => hash[namevar])
-
- # We can't just pass the hash in at object creation time,
- # because it sets the should value, not the is value.
- hash.delete(namevar)
- hash.each { |param, value|
- obj.is = [param, value]
- }
+ else
+ # We don't do the work here, it gets done in 'store'
+ tail = "changed"
+ end
+ @synced = self.should
+
+ # This should really only be done once per run, rather than
+ # every time. I guess we need some kind of 'flush' mechanism.
+ if nostore
+ self.retrieve
+ else
+ @parent.store
+ end
+
+ return (ebase + "_" + tail).intern
end
end
+ end
- # Override 'newstate' so that all states default to having the
- # correct parent type
- def self.newstate(name, options = {}, &block)
- options[:parent] ||= Puppet::State::ParsedParam
- super(name, options, &block)
- end
+ class Type
+ # The collection of classes that are just simple records aggregated
+ # into a file. See 'host.rb' for an example.
+ class ParsedType < Puppet::Type
+ @name = :parsedtype
+ class << self
+ attr_accessor :filetype, :hostfile, :fields
+ attr_reader :path
+ attr_writer :fileobj
+ end
- def self.list
- retrieve.collect { |i| i.is_a? Hash }.collect { |i| hash2obj(i) }
- end
+ # Override 'newstate' so that all states default to having the
+ # correct parent type
+ def self.newstate(name, options = {}, &block)
+ options[:parent] ||= Puppet::State::ParsedParam
+ super(name, options, &block)
+ end
- def self.listbyname
- retrieve.collect { |i| i.is_a? Hash }.collect { |i| i[:name] }
- end
+ # Add another type var.
+ def self.initvars
+ @instances = []
+ super
+ end
- # Make sure they've got an explicit :ensure class.
- def self.postinit
- unless validstate? :ensure
- newstate(:ensure) do
- newvalue(:present) do
- # The value will get flushed appropriately
- return nil
- end
+ # In addition to removing the instances in @objects, we have to remove
+ # per-user host tab information.
+ def self.clear
+ @instances = []
+ @fileobj = nil
+ super
+ end
- newvalue(:absent) do
- # The value will get flushed appropriately
- return nil
- end
+ # Add a non-object comment or whatever to our list of instances
+ def self.comment(line)
+ @instances << line
+ end
+
+ # Override the default Puppet::Type method, because instances
+ # also need to be deleted from the @instances hash
+ def self.delete(child)
+ if @instances.include?(child)
+ @instances.delete(child)
+ end
+ super
+ end
+
+ # Initialize the object if necessary.
+ def self.fileobj
+ @fileobj ||= @filetype.new(@path)
+
+ @fileobj
+ end
+
+ # Return the header placed at the top of each generated file, warning
+ # users that modifying this file manually is probably a bad idea.
+ def self.header
+%{# HEADER: This file was autogenerated at #{Time.now}
+# HEADER: by puppet. While it can still be managed manually, it
+# HEADER: is definitely not recommended.\n}
+ end
+
+ # Convert the hash to an object.
+ def self.hash2obj(hash)
+ obj = nil
- defaultto do
- if @parent.managed?
- :present
+ namevar = self.namevar
+ unless hash.include?(namevar) and hash[namevar]
+ raise Puppet::DevError, "Hash was not passed with namevar"
+ end
+
+ # if the obj already exists with that name...
+ if obj = self[hash[namevar]]
+ # We're assuming here that objects with the same name
+ # are the same object, which *should* be the case, assuming
+ # we've set up our naming stuff correctly everywhere.
+
+ # Mark found objects as present
+ obj.is = [:ensure, :present]
+ hash.each { |param, value|
+ if state = obj.state(param)
+ state.is = value
+ elsif val = obj[param]
+ obj[param] = val
else
- nil
+ # There is a value on disk, but it should go away
+ obj.is = [param, value]
+ obj[param] = :absent
end
- end
+ }
+ else
+ # create a new obj, since no existing one seems to
+ # match
+ obj = self.create(namevar => hash[namevar])
+
+ # We can't just pass the hash in at object creation time,
+ # because it sets the should value, not the is value.
+ hash.delete(namevar)
+ hash.each { |param, value|
+ obj.is = [param, value]
+ }
end
+
+ # And then add it to our list of instances. This maintains the order
+ # in the file.
+ @instances << obj
end
- end
- def exists?
- h = self.retrieve
+ def self.list
+ retrieve
- if h[:ensure] == :absent
- return false
- else
- return true
+ self.collect do |obj|
+ obj
+ end
end
- end
- # Flush our content to disk.
- def flush
- provider.store(self.to_hash)
- end
+ # Return the last time the file was loaded. Could
+ # be used for reducing writes, but currently is not.
+ def self.loaded?(user)
+ fileobj().loaded
+ end
- # Retrieve our current state from our provider
- def retrieve
- h = nil
- if h = provider.hash and ! h.empty?
- h[:ensure] ||= :present
-
- # If they passed back info we don't have, then mark it to
- # be deleted.
- h.each do |name, value|
- next unless self.class.validstate?(name)
- unless @states.has_key? name
- self.newstate(name, :should => :absent)
- end
+ # Parse a file
+ #
+ # Subclasses must override this method.
+ def self.parse(text)
+ raise Puppet::DevError, "Parse was not overridden in %s" %
+ self.name
+ end
+
+ # If they change the path, we need to get rid of our cache object
+ def self.path=(path)
+ @fileobj = nil
+ @path = path
+ end
+
+ # Retrieve the text for the file. Returns nil in the unlikely
+ # event that it doesn't exist.
+ def self.retrieve
+ text = fileobj.read
+ if text.nil? or text == ""
+ # there is no file
+ return nil
+ else
+ # First we mark all of our objects absent; any objects
+ # subsequently found will be marked present
+ self.each { |obj|
+ obj.is = [:ensure, :absent]
+ }
+
+ # We clear this, so that non-objects don't get duplicated
+ @instances.clear
+ self.parse(text)
end
+ end
- @states.each do |name, state|
- unless h.has_key? name
- h[name] = :absent
- end
+ # Write out the file.
+ def self.store
+ # Make sure all of our instances are in the to-be-written array
+ self.each do |inst|
+ @instances << inst unless @instances.include? inst
+ end
+
+ if @instances.empty?
+ Puppet.notice "No %s instances for %s" % [self.name, @path]
+ else
+ fileobj.write(self.to_file())
end
- return h
- else
- h = {}
- @states.each do |name, state|
- h[name] = :absent
+ end
+
+ # Collect all Host instances convert them into literal text.
+ def self.to_file
+ str = self.header()
+ unless @instances.empty?
+ str += @instances.reject { |obj|
+ # Don't write out objects that should be absent
+ if obj.is_a?(self)
+ if obj.should(:ensure) == :absent
+ true
+ end
+ end
+ }.collect { |obj|
+ if obj.is_a?(self)
+ obj.to_record
+ else
+ obj.to_s
+ end
+ }.join("\n") + "\n"
+
+ return str
+ else
+ Puppet.notice "No %s instances" % self.name
+ return ""
end
end
- return h
+ # The 'store' method knows how to handle absence vs. presence
+ def create
+ self.store
+ end
+
+ # The 'store' method knows how to handle absence vs. presence
+ def destroy
+ self.store
+ end
+
+ # hash2obj marks the 'ensure' state as present
+ def exists?
+ @states.include?(:ensure) and @states[:ensure].is == :present
+ end
+
+ # Override the default Puppet::Type method because we need to call
+ # the +@filetype+ retrieve method.
+ def retrieve
+ self.class.retrieve()
+
+ self.eachstate { |st|
+ st.retrieve
+ }
+ end
+
+ # Write the entire file out.
+ def store
+ self.class.store()
+ end
+
+ def value(name)
+ unless name.is_a? Symbol
+ name = name.intern
+ end
+ if @states.include? name
+ val = @states[name].value
+ if val == :absent
+ return nil
+ else
+ return val
+ end
+ elsif @parameters.include? name
+ return @parameters[name].value
+ else
+ return nil
+ end
+ end
end
end
end
+require 'puppet/type/parsedtype/host'
+require 'puppet/type/parsedtype/port'
+require 'puppet/type/parsedtype/mount'
+require 'puppet/type/parsedtype/sshkey'
+
# $Id$
diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/parsedtype/host.rb
index d68fe25a2..00cfe7857 100755
--- a/lib/puppet/type/host.rb
+++ b/lib/puppet/type/parsedtype/host.rb
@@ -1,7 +1,11 @@
+require 'etc'
+require 'facter'
require 'puppet/type/parsedtype'
+require 'puppet/type/state'
module Puppet
newtype(:host, Puppet::Type::ParsedType) do
+
newstate(:ip) do
desc "The host's IP address."
end
@@ -13,19 +17,6 @@ module Puppet
make those aliases available in your Puppet scripts and also on
disk."
- # Make sure our "is" value is always an array.
- def is
- current = super
- unless current.is_a? Array
- current = [current]
- end
- current
- end
-
- def is_to_s
- self.is.join(" ")
- end
-
# We have to override the feeding mechanism; it might be nil or
# white-space separated
def is=(value)
@@ -84,6 +75,69 @@ module Puppet
@doc = "Installs and manages host entries. For most systems, these
entries will just be in /etc/hosts, but some systems (notably OS X)
will have different solutions."
+
+ @instances = []
+
+ @path = "/etc/hosts"
+ @fields = [:ip, :name, :alias]
+
+ @filetype = Puppet::FileType.filetype(:flat)
+
+ # Parse a host file
+ #
+ # This method also stores existing comments, and it stores all host
+ # jobs in order, mostly so that comments are retained in the order
+ # they were written and in proximity to the same jobs.
+ def self.parse(text)
+ count = 0
+ hash = {}
+ text.chomp.split("\n").each { |line|
+ case line
+ when /^#/, /^\s*$/:
+ # add comments and blank lines to the list as they are
+ @instances << line
+ else
+ if line.sub!(/^(\S+)\s+(\S+)\s*/, '')
+ hash[:ip] = $1
+ hash[:name] = $2
+
+ unless line == ""
+ line.sub!(/\s*/, '')
+ line.sub!(/^([^#]+)\s*/) do |value|
+ aliases = $1
+ unless aliases =~ /^\s*$/
+ hash[:alias] = aliases
+ end
+
+ ""
+ end
+ end
+ else
+ raise Puppet::Error, "Could not match '%s'" % line
+ end
+
+ if hash[:alias] == ""
+ hash.delete(:alias)
+ end
+
+ hash2obj(hash)
+
+ hash.clear
+ count += 1
+ end
+ }
+ end
+
+ # Convert the current object into a host-style string.
+ def to_record
+ str = "%s\t%s" % [self.state(:ip).value, self[:name]]
+
+ if value = self.value(:alias)
+ str += "\t%s" % value.join("\t")
+ end
+
+ str
+ end
end
end
diff --git a/lib/puppet/type/parsedtype/mount.rb b/lib/puppet/type/parsedtype/mount.rb
new file mode 100755
index 000000000..3f186ddca
--- /dev/null
+++ b/lib/puppet/type/parsedtype/mount.rb
@@ -0,0 +1,271 @@
+require 'etc'
+require 'facter'
+require 'puppet/type/parsedtype'
+require 'puppet/type/state'
+
+module Puppet
+ newtype(:mount, Puppet::Type::ParsedType) do
+ ensurable do
+ desc "Control what to do with this mount. If the value is
+ ``present``, the mount is entered into the mount table,
+ but not mounted, if it is ``absent``, the entry is removed
+ from the mount table and the filesystem is unmounted if
+ currently mounted, if it is ``mounted``, the filesystem
+ is entered into the mount table and mounted."
+
+ newvalue(:present) do
+ @parent.create()
+ end
+
+ newvalue(:absent) do
+ @parent.destroy()
+
+ if @parent.mounted?
+ @parent.unmount
+ end
+
+ :mount_removed
+ end
+
+ newvalue(:mounted) do
+ if @is == :absent
+ set_present
+ end
+
+ @parent.mount
+
+ :mount_mounted
+ end
+
+ def retrieve
+ if @parent.mounted?
+ @is = :mounted
+ else
+ val = super()
+ @is = val
+ end
+ end
+ end
+
+ newstate(:device) do
+ desc "The device providing the mount. This can be whatever
+ device is supporting by the mount, including network
+ devices or devices specified by UUID rather than device
+ path, depending on the operating system."
+ end
+
+ # Solaris specifies two devices, not just one.
+ newstate(:blockdevice) do
+ desc "The the device to fsck. This is state is only valid
+ on Solaris, and in most cases will default to the correct
+ value."
+
+ # Default to the device but with "dsk" replaced with "rdsk".
+ defaultto do
+ if Facter["operatingsystem"].value == "Solaris"
+ device = @parent.value(:device)
+ if device =~ %r{/dsk/}
+ device.sub(%r{/dsk/}, "/rdsk/")
+ else
+ nil
+ end
+ else
+ nil
+ end
+ end
+ end
+
+ newstate(:fstype) do
+ desc "The mount type. Valid values depend on the
+ operating system."
+ end
+
+ newstate(:options) do
+ desc "Mount options for the mounts, as they would
+ appear in the fstab."
+ end
+
+ newstate(:pass) do
+ desc "The pass in which the mount is checked."
+ end
+
+ newstate(:atboot) do
+ desc "Whether to mount the mount at boot. Not all platforms
+ support this."
+ end
+
+ newstate(:dump) do
+ desc "Whether to dump the mount. Not all platforms
+ support this."
+ end
+
+ newparam(:path) do
+ desc "The mount path for the mount."
+
+ isnamevar
+ end
+
+ @doc = "Manages mounted mounts, including putting mount
+ information into the mount table. The actual behavior depends
+ on the value of the 'ensure' parameter."
+
+ def self.init
+ @platform = Facter["operatingsystem"].value
+ case @platform
+ when "Solaris":
+ @path = "/etc/vfstab"
+ @fields = [:device, :blockdevice, :path, :fstype, :pass, :atboot,
+ :options]
+ @defaults = [ nil ] * @fields.size
+ when "Darwin":
+ @filetype = Puppet::FileType.filetype(:netinfo)
+ @filetype.format = "fstab"
+ @path = "mounts"
+ @fields = [:device, :path, :fstype, :options, :dump, :pass]
+ @defaults = [ nil ] * @fields.size
+
+ # How to map the dumped table to what we want
+ @fieldnames = {
+ "name" => :device,
+ "dir" => :path,
+ "dump_freq" => :dump,
+ "passno" => :pass,
+ "vfstype" => :fstype,
+ "opts" => :options
+ }
+ else
+ @path = "/etc/fstab"
+ @fields = [:device, :path, :fstype, :options, :dump, :pass]
+ @defaults = [ nil ] * 4 + [ "0", "2" ]
+ end
+
+ # Allow Darwin to override the default filetype
+ unless defined? @filetype
+ @filetype = Puppet::FileType.filetype(:flat)
+ end
+ end
+
+ init
+
+ def self.clear
+ init
+ super
+ end
+
+ # Parse a mount tab.
+ #
+ # This method also stores existing comments, and it stores all
+ # mounts in order, mostly so that comments are retained in the
+ # order they were written and in proximity to the same fses.
+ def self.parse(text)
+ # provide a single exception for darwin & netinfo
+ if @filetype == Puppet::FileType.filetype(:netinfo)
+ parseninfo(text)
+ return
+ end
+ count = 0
+ hash = {}
+ text.chomp.split("\n").each { |line|
+ case line
+ when /^#/, /^\s*$/:
+ # add comments and blank lines to the list as they are
+ comment(line)
+ else
+ values = line.split(/\s+/)
+ if @fields.length < values.length
+ raise Puppet::Error, "Could not parse line %s" % line
+ end
+
+ values = @defaults.zip(values).collect { |d, v| v || d }
+ unless @fields.length == values.length
+ raise Puppet::Error, "Could not parse line %s" % line
+ end
+
+ @fields.zip(values).each do |field, value|
+ hash[field] = value
+ end
+
+ hash2obj(hash)
+
+ hash.clear
+ count += 1
+ end
+ }
+ end
+
+ # Parse a netinfo table.
+ def self.parseninfo(text)
+ array = @fileobj.to_array(text)
+
+ hash = {}
+ array.each do |record|
+ @fieldnames.each do |name, field|
+ if value = record[name]
+ if field == :options
+ hash[field] = value.join(",")
+ else
+ hash[field] = value[0]
+ end
+ else
+ raise ArgumentError, "Field %s was not provided" % [name]
+ end
+ end
+
+
+ hash2obj(hash)
+ hash.clear
+ end
+ end
+
+ # This only works when the mount point is synced to the fstab.
+ def mount
+ output = %x{mount #{self[:path]} 2>&1}
+
+ unless $? == 0
+ raise Puppet::Error, "Could not mount %s: %s" % [self[:path], output]
+ end
+ end
+
+ # This only works when the mount point is synced to the fstab.
+ def unmount
+ output = %x{umount #{self[:path]}}
+
+ unless $? == 0
+ raise Puppet::Error, "Could not mount %s" % self[:path]
+ end
+ end
+
+ # Is the mount currently mounted?
+ def mounted?
+ platform = Facter["operatingsystem"].value
+ df = "df"
+ case Facter["operatingsystem"].value
+ # Solaris's df prints in a very weird format
+ when "Solaris": df = "df -k"
+ end
+ %x{#{df}}.split("\n").find do |line|
+ fs = line.split(/\s+/)[-1]
+ if platform == "Darwin"
+ fs == "/private/var/automount" + self[:path] or
+ fs == self[:path]
+ else
+ fs == self[:path]
+ end
+ end
+ end
+
+ # Convert the current object into an fstab-style string.
+ def to_record
+ self.class.fields.collect do |field|
+ if value = self.value(field)
+ value
+ else
+ raise Puppet::Error,
+ "Could not retrieve value for %s" % field
+ end
+ end.join("\t")
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/parsedtype/port.rb b/lib/puppet/type/parsedtype/port.rb
new file mode 100755
index 000000000..f8a08913f
--- /dev/null
+++ b/lib/puppet/type/parsedtype/port.rb
@@ -0,0 +1,261 @@
+require 'etc'
+require 'facter'
+require 'puppet/type/parsedtype'
+require 'puppet/type/state'
+
+module Puppet
+ newtype(:port, Puppet::Type::ParsedType) do
+ newstate(:protocols) do
+ desc "The protocols the port uses. Valid values are *udp* and *tcp*.
+ Most services have both protocols, but not all. If you want
+ both protocols, you must specify that; Puppet replaces the
+ current values, it does not merge with them. If you specify
+ multiple protocols they must be as an array."
+
+ def is=(value)
+ case value
+ when String
+ @is = value.split(/\s+/)
+ else
+ @is = value
+ end
+ end
+
+ def is
+ @is
+ end
+
+ # We actually want to return the whole array here, not just the first
+ # value.
+ def should
+ if defined? @should
+ if @should[0] == :absent
+ return :absent
+ else
+ return @should
+ end
+ else
+ return nil
+ end
+ end
+
+ validate do |value|
+ valids = ["udp", "tcp", "ddp", :absent]
+ unless valids.include? value
+ raise Puppet::Error,
+ "Protocols can be either 'udp' or 'tcp', not %s" % value
+ end
+ end
+ end
+
+ newstate(:number) do
+ desc "The port number."
+ end
+
+ newstate(:description) do
+ desc "The port description."
+ isoptional
+ end
+
+ newstate(:alias) do
+ desc "Any aliases the port might have. Multiple values must be
+ specified as an array. Note that this state has the same name as
+ one of the metaparams; using this state to set aliases will make
+ those aliases available in your Puppet scripts and also on disk."
+
+ isoptional
+
+ # We have to override the feeding mechanism; it might be nil or
+ # white-space separated
+ def is=(value)
+ # If it's just whitespace, ignore it
+ case value
+ when /^\s+$/
+ @is = nil
+ when String
+ @is = value.split(/\s+/)
+ when Symbol
+ @is = value
+ else
+ raise Puppet::DevError, "Invalid value %s" % value.inspect
+ end
+ end
+
+ # We actually want to return the whole array here, not just the first
+ # value.
+ def should
+ if defined? @should
+ if @should[0] == :absent
+ return :absent
+ else
+ return @should
+ end
+ else
+ return nil
+ end
+ end
+
+ validate do |value|
+ if value.is_a? String and value =~ /\s/
+ raise Puppet::Error,
+ "Aliases cannot have whitespace in them: %s" %
+ value.inspect
+ end
+ end
+
+ munge do |value|
+ unless value == "absent" or value == :absent
+ # Add the :alias metaparam in addition to the state
+ @parent.newmetaparam(
+ @parent.class.metaparamclass(:alias), value
+ )
+ end
+ value
+ end
+ end
+
+ newparam(:name) do
+ desc "The port name."
+
+ isnamevar
+ end
+
+ @doc = "Installs and manages port entries. For most systems, these
+ entries will just be in /etc/services, but some systems (notably OS X)
+ will have different solutions."
+
+ @path = "/etc/services"
+ @fields = [:ip, :name, :alias]
+
+ @filetype = Puppet::FileType.filetype(:flat)
+
+ # 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
+ hash = {}
+ text.chomp.split("\n").each { |line|
+ hash.clear
+ 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
+ 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 = self[hash[:name]]
+ if obj.portmerge(hash)
+ next
+ end
+ end
+
+ hash2obj(hash)
+
+ count += 1
+ end
+ }
+ end
+
+ def portmerge(hash)
+ unless @states.include?(:protocols)
+ return false
+ end
+
+ # This method is only called from parsing, so we only worry
+ # about 'is' values.
+ proto = self.state(:protocols).is
+
+ if proto.nil? or proto == :absent
+ # We are an unitialized object; we've got 'should'
+ # values but no 'is' values
+ return false
+ end
+
+ # If this is happening, our object exists
+ self.is = [:ensure, :present]
+
+ if hash[:protocols]
+ # The protocol can be a symbol, so...
+ if proto.is_a?(Symbol)
+ proto = []
+ end
+ # Check to see if it already includes our proto
+ unless proto.include?(hash[:protocols])
+ # We are missing their proto
+ proto << hash[:protocols]
+ @states[:protocols].is = proto
+ end
+ end
+
+ if hash.include?(:description) and ! @states.include?(:description)
+ self.is = [:description, hash[:description]]
+ end
+
+ return true
+ end
+
+ # Convert the current object into one or more services entry.
+ def to_record
+ self.state(:protocols).value.collect { |proto|
+ str = "%s\t%s/%s" % [self[:name], self.value(:number),
+ proto]
+
+ if value = self.value(:alias) and value != :absent
+ str += "\t%s" % value.join(" ")
+ else
+ str += "\t"
+ end
+
+ if value = self.value(:description) and value != :absent
+ str += "\t# %s" % value
+ else
+ str += "\t"
+ end
+ str
+ }.join("\n")
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/parsedtype/sshkey.rb b/lib/puppet/type/parsedtype/sshkey.rb
new file mode 100755
index 000000000..d12d4c697
--- /dev/null
+++ b/lib/puppet/type/parsedtype/sshkey.rb
@@ -0,0 +1,123 @@
+require 'etc'
+require 'facter'
+require 'puppet/type/parsedtype'
+require 'puppet/type/state'
+
+module Puppet
+ newtype(:sshkey, Puppet::Type::ParsedType) do
+ newstate(:type) do
+ desc "The encryption type used. Probably ssh-dss or ssh-rsa."
+ end
+
+ newstate(:key) do
+ desc "The key itself; generally a long string of hex digits."
+ end
+
+ # FIXME This should automagically check for aliases to the hosts, just
+ # to see if we can automatically glean any aliases.
+ newstate(:alias) do
+ desc "Any alias the host might have. Multiple values must be
+ specified as an array. Note that this state has the same name
+ as one of the metaparams; using this state to set aliases will
+ make those aliases available in your Puppet scripts."
+
+ # We actually want to return the whole array here, not just the first
+ # value.
+ def should
+ if defined? @should
+ return @should
+ else
+ return nil
+ end
+ end
+
+ validate do |value|
+ if value =~ /\s/
+ raise Puppet::Error, "Aliases cannot include whitespace"
+ end
+ if value =~ /,/
+ raise Puppet::Error, "Aliases cannot include whitespace"
+ end
+ end
+
+ # Make a puppet alias in addition.
+ munge do |value|
+ # Add the :alias metaparam in addition to the state
+ @parent.newmetaparam(@parent.class.metaparamclass(:alias), value)
+ value
+ end
+ end
+
+ newparam(:name) do
+ desc "The host name."
+
+ isnamevar
+ end
+
+ @doc = "Installs and manages ssh host keys. At this point, this type
+ only knows how to install keys into /etc/ssh/ssh_known_hosts, and
+ it cannot manage user authorized keys yet."
+
+ @instances = []
+
+ # FIXME This should be configurable.
+ @path = "/etc/ssh/ssh_known_hosts"
+ @fields = [:name, :type, :key]
+
+ @filetype = Puppet::FileType.filetype(:flat)
+# case Facter["operatingsystem"].value
+# when "Solaris":
+# @filetype = Puppet::FileType::SunOS
+# else
+# @filetype = Puppet::CronType::Default
+# end
+
+ # Parse a host file
+ #
+ # This method also stores existing comments, and it stores all host
+ # jobs in order, mostly so that comments are retained in the order
+ # they were written and in proximity to the same jobs.
+ def self.parse(text)
+ count = 0
+ hash = {}
+ text.chomp.split("\n").each { |line|
+ case line
+ when /^#/, /^\s*$/:
+ # add comments and blank lines to the list as they are
+ @instances << line
+ else
+ hash = {}
+ fields().zip(line.split(" ")).each { |param, value|
+ hash[param] = value
+ }
+
+ if hash[:name] =~ /,/
+ names = hash[:name].split(",")
+ hash[:name] = names.shift
+ hash[:alias] = names
+ end
+
+ if hash[:alias] == ""
+ hash.delete(:alias)
+ end
+
+ hash2obj(hash)
+
+ hash.clear
+ count += 1
+ end
+ }
+ end
+
+ # Convert the current object into a host-style string.
+ def to_record
+ name = self[:name]
+ if @states.include?(:alias)
+ name += "," + @states[:alias].value.join(",")
+ end
+ [name, @states[:type].value, @states[:key].value].join(" ")
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb
index ac892c069..ec666497d 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/pfile.rb
@@ -691,7 +691,7 @@ module Puppet
if child = self.newchild(file, true, options)
# Mark any unmanaged files for removal if purge is set.
- if self[:purge] == :true and ! child.managed?
+ if self[:purge] == :true and child.implicit?
child[:ensure] = :absent
end
@@ -761,8 +761,6 @@ module Puppet
# a wrapper method to make sure the file exists before doing anything
def retrieve
- is = {}
-
if @states.include?(:source)
# This probably isn't the best place for it, but we need
# to make sure that we have a corresponding checksum state.
@@ -772,35 +770,35 @@ module Puppet
# We have to retrieve the source info before the recursion happens,
# although I'm not exactly clear on why.
- is[:source] = @states[:source].retrieve
+ @states[:source].retrieve
end
if @parameters.include?(:recurse)
self.recurse
end
- if stat = self.stat(true)
- states().each { |state|
- # We don't want to call 'describe()' twice, so only do a local
- # retrieve on the source.
- if state.name == :source
- is[state.name] = state.retrieve(false)
- else
- is[state.name] = state.retrieve
- end
- }
- else
+ unless stat = self.stat(true)
self.debug "File does not exist"
@states.each { |name,state|
# We've already retreived the source, and we don't
# want to overwrite whatever it did. This is a bit
# of a hack, but oh well, source is definitely special.
next if name == :source
- is[name] = :absent
+ state.is = :absent
}
+
+ return
end
- return is
+ states().each { |state|
+ # We don't want to call 'describe()' twice, so only do a local
+ # retrieve on the source.
+ if state.name == :source
+ state.retrieve(false)
+ else
+ state.retrieve
+ end
+ }
end
# Set the checksum, from another state. There are multiple states that
diff --git a/lib/puppet/type/pfile/checksum.rb b/lib/puppet/type/pfile/checksum.rb
index 514c47690..cd82a4439 100755
--- a/lib/puppet/type/pfile/checksum.rb
+++ b/lib/puppet/type/pfile/checksum.rb
@@ -191,7 +191,7 @@ module Puppet
if self.insync?
self.debug "Checksum is already in sync"
- return :nochange
+ return nil
end
#@parent.debug "%s(%s): after refresh, is '%s'" %
# [self.class.name,@parent.name,@is]
@@ -207,7 +207,7 @@ module Puppet
@parent[:path]
)
end
- return :nochange
+ return nil
end
end
@@ -215,7 +215,7 @@ module Puppet
if self.updatesum
return :file_changed
else
- return :nochange
+ return nil
end
end
@@ -270,8 +270,6 @@ module Puppet
end
#@parent.debug "checksum state is %s" % self.is
-
- return @is
end
# Store the new sum to the state db.
diff --git a/lib/puppet/type/pfile/content.rb b/lib/puppet/type/pfile/content.rb
index 3eb875dc2..a8422431f 100755
--- a/lib/puppet/type/pfile/content.rb
+++ b/lib/puppet/type/pfile/content.rb
@@ -29,36 +29,36 @@ module Puppet
def retrieve
stat = nil
unless stat = @parent.stat
- return :absent
+ @is = :absent
+ return
end
if stat.ftype == "link" and @parent[:links] == :ignore
- return self.should
+ self.is = self.should
+ return
end
# Don't even try to manage the content on directories
if stat.ftype == "directory" and @parent[:links] == :ignore
@parent.delete(:content)
- return :notmanaged
+ return
end
begin
- retval = File.read(@parent[:path])
+ @is = File.read(@parent[:path])
rescue => detail
- retval = :unknown
+ @is = nil
raise Puppet::Error, "Could not read %s: %s" %
[@parent.title, detail]
end
-
- return retval
end
# Just write our content out to disk.
- def sync(value)
- @parent.write { |f| f.print value }
+ def sync
+ @parent.write { |f| f.print self.should }
- if self.is == :absent
+ if @is == :absent
return :file_created
else
return :file_changed
diff --git a/lib/puppet/type/pfile/ensure.rb b/lib/puppet/type/pfile/ensure.rb
index 0debc245a..ac045dfd6 100755
--- a/lib/puppet/type/pfile/ensure.rb
+++ b/lib/puppet/type/pfile/ensure.rb
@@ -35,25 +35,19 @@ module Puppet
# Most 'ensure' states have a default, but with files we, um, don't.
nodefault
- newvalue(:absent, :event => :file_deleted) do
+ newvalue(:absent) do
File.unlink(@parent[:path])
end
aliasvalue(:false, :absent)
- newvalue(:file, :event => :file_created) do
+ newvalue(:file) do
# Make sure we're not managing the content some other way
- if state = (@parent.state(:content) || @parent.state(:source))
- # Manually sync the state, and reset its is value to it knows it's
- # in sync.
- should = state.should
- state.commit
-
- # The 'sync' method here syncs any states that might still be
- # out of sync like 'mode', so we need to mark this in sync.
- state.is = should
+ if state = @parent.state(:content) or state = @parent.state(:source)
+ state.sync
else
@parent.write(false) { |f| f.flush }
+ mode = @parent.should(:mode)
end
return :file_created
end
@@ -65,7 +59,7 @@ module Puppet
set_file
end
- newvalue(:directory, :event => :directory_created) do
+ newvalue(:directory) do
mode = @parent.should(:mode)
parent = File.dirname(@parent[:path])
unless FileTest.exists? parent
@@ -87,7 +81,7 @@ module Puppet
end
- newvalue(:link, :event => :link_created) do
+ newvalue(:link) do
if state = @parent.state(:target)
state.retrieve
@@ -103,7 +97,7 @@ module Puppet
end
# Symlinks.
- newvalue(/./, :event => :link_created) do
+ newvalue(/./) do
# This code never gets executed. We need the regex to support
# specifying it, but the work is done in the 'symlink' code block.
end
@@ -136,9 +130,8 @@ module Puppet
# We have to treat :present specially, because it works with any
# type of file.
def insync?
- is = self.is
if self.should == :present
- if is.nil? or is == :absent
+ if @is.nil? or @is == :absent
return false
else
return true
@@ -149,22 +142,19 @@ module Puppet
end
def retrieve
- retval = nil
if stat = @parent.stat(false)
- retval = stat.ftype.intern
+ @is = stat.ftype.intern
else
if self.should == :false
- retval = :false
+ @is = :false
else
- retval = :absent
+ @is = :absent
end
end
-
- return retval
end
- def sync(value)
- event = super(value)
+ def sync
+ event = super
# There are some cases where all of the work does not get done on
# file creation, so we have to do some extra checking.
@@ -174,7 +164,7 @@ module Puppet
thing.retrieve
unless thing.insync?
- thing.commit
+ thing.sync
end
end
diff --git a/lib/puppet/type/pfile/group.rb b/lib/puppet/type/pfile/group.rb
index ce6d43422..9431b0e65 100755
--- a/lib/puppet/type/pfile/group.rb
+++ b/lib/puppet/type/pfile/group.rb
@@ -41,7 +41,8 @@ module Puppet
stat = @parent.stat(false)
unless stat
- return :absent
+ self.is = :absent
+ return
end
# Set our method appropriately, depending on links.
@@ -50,7 +51,7 @@ module Puppet
else
@method = :chown
end
- return stat.gid
+ self.is = stat.gid
end
# Determine if the group is valid, and if so, return the UID
@@ -81,7 +82,7 @@ module Puppet
# Normal users will only be able to manage certain groups. Right now,
# we'll just let it fail, but we should probably set things up so
# that users get warned if they try to change to an unacceptable group.
- def sync(value)
+ def sync
if @is == :absent
@parent.stat(true)
self.retrieve
@@ -89,17 +90,17 @@ module Puppet
if @is == :absent
self.debug "File '%s' does not exist; cannot chgrp" %
@parent[:path]
- return :nochange
+ return nil
end
if self.insync?
- return :nochange
+ return nil
end
end
gid = nil
- unless gid = Puppet::Util.gid(value)
- raise Puppet::Error, "Could not find group %s" % value
+ unless gid = Puppet::Util.gid(self.should)
+ raise Puppet::Error, "Could not find group %s" % self.should
end
begin
@@ -107,7 +108,7 @@ module Puppet
File.send(@method,nil,gid,@parent[:path])
rescue => detail
error = Puppet::Error.new( "failed to chgrp %s to %s: %s" %
- [@parent[:path], value, detail.message])
+ [@parent[:path], self.should, detail.message])
raise error
end
return :file_changed
diff --git a/lib/puppet/type/pfile/mode.rb b/lib/puppet/type/pfile/mode.rb
index 9dd993682..ee6fb37d8 100755
--- a/lib/puppet/type/pfile/mode.rb
+++ b/lib/puppet/type/pfile/mode.rb
@@ -89,35 +89,35 @@ module Puppet
# off mode management entirely.
if stat = @parent.stat(false)
+ self.is = stat.mode & 007777
unless defined? @fixed
if defined? @should and @should
@should = @should.collect { |s| self.dirmask(s) }
end
end
- return stat.mode & 007777
else
- return :absent
+ self.is = :absent
end
#self.debug "chmod state is %o" % self.is
end
- def sync(value)
+ def sync
if @is == :absent
@parent.stat(true)
self.retrieve
if @is == :absent
self.debug "File does not exist; cannot set mode"
- return :nochange
+ return nil
end
if self.insync?
# we're already in sync
- return :nochange
+ return nil
end
end
- mode = value
+ mode = self.should
if mode == :absent
# This is really only valid for create states...
diff --git a/lib/puppet/type/pfile/source.rb b/lib/puppet/type/pfile/source.rb
index 057673457..744d66f34 100755
--- a/lib/puppet/type/pfile/source.rb
+++ b/lib/puppet/type/pfile/source.rb
@@ -116,7 +116,6 @@ module Puppet
return nil
end
- retval = nil
# If we're a normal file, then set things up to copy the file down.
case @stats[:type]
when "file":
@@ -125,20 +124,20 @@ module Puppet
if sum.is == :absent
sum.retrieve(true)
end
- retval = sum.is
+ @is = sum.is
else
- retval = :absent
+ @is = :absent
end
else
self.info "File does not have checksum"
- retval = :absent
+ @is = :absent
end
# if replace => false then fake the checksum so that the file
# is not overwritten.
- unless retval == :absent
+ unless @is == :absent
if @parent[:replace] == :false
info "Not replacing existing file"
- retval = @stats[:checksum]
+ @is = @stats[:checksum]
end
end
@should = [@stats[:checksum]]
@@ -155,11 +154,11 @@ module Puppet
end
# we'll let the :ensure state do our work
@should.clear
- retval = true
+ @is = true
when "link":
case @parent[:links]
when :ignore
- retval = :nocopy
+ @is = :nocopy
@should = [:nocopy]
self.info "Ignoring link %s" % @source
return
@@ -176,7 +175,7 @@ module Puppet
self.err "Cannot use files of type %s as sources" %
@stats[:type]
@should = [:nocopy]
- retval = :nocopy
+ @is = :nocopy
end
# Take each of the stats and set them as states on the local file
@@ -197,8 +196,6 @@ module Puppet
# @parent.info "Already specified %s" % stat
end
}
-
- return retval
end
# The special thing here is that we need to make sure that 'should'
@@ -229,19 +226,22 @@ module Puppet
end
end
- def sync(value)
+ def sync
if @is == :notdescribed
self.retrieve # try again
if @is == :notdescribed
@parent.log "Could not retreive information on %s" %
@parent.title
- return :nochange
+ return nil
end
if @is == @should
- return :nochange
+ return nil
end
end
+ case @stats[:type]
+ when "link":
+ end
unless @stats[:type] == "file"
#if @stats[:type] == "directory"
#[@parent.name, @is.inspect, @should.inspect]
diff --git a/lib/puppet/type/pfile/target.rb b/lib/puppet/type/pfile/target.rb
index 6bdc408f2..4a725d652 100644
--- a/lib/puppet/type/pfile/target.rb
+++ b/lib/puppet/type/pfile/target.rb
@@ -56,8 +56,8 @@ module Puppet
def retrieve
if @parent.state(:ensure).should == :directory
+ @is = self.should
@linkmaker = true
- return self.should
else
if stat = @parent.stat
# If we're just checking the value
@@ -73,18 +73,18 @@ module Puppet
warning "Changing ensure to directory; recurse is %s but %s" %
[@parent[:recurse].inspect, @parent.recurse?]
@parent[:ensure] = :directory
+ @is = should
@linkmaker = true
- return should
else
if stat.ftype == "link"
+ @is = File.readlink(@parent[:path])
@linkmaker = false
- return File.readlink(@parent[:path])
else
- return :notlink
+ @is = :notlink
end
end
else
- return :absent
+ @is = :absent
end
end
end
diff --git a/lib/puppet/type/pfile/type.rb b/lib/puppet/type/pfile/type.rb
index 4a7b9641d..e5db7d694 100755
--- a/lib/puppet/type/pfile/type.rb
+++ b/lib/puppet/type/pfile/type.rb
@@ -8,21 +8,18 @@ module Puppet
#end
def retrieve
- retval = nil
if stat = @parent.stat(false)
- retval = stat.ftype
+ @is = stat.ftype
else
- retval = :absent
+ @is = :absent
end
# so this state is never marked out of sync
- @should = [retval]
-
- return retval
+ @should = [@is]
end
- def sync(value)
+ def sync
raise Puppet::Error, ":type is read-only"
end
end
diff --git a/lib/puppet/type/pfile/uid.rb b/lib/puppet/type/pfile/uid.rb
index e05ba4f4c..a492b31f4 100755
--- a/lib/puppet/type/pfile/uid.rb
+++ b/lib/puppet/type/pfile/uid.rb
@@ -81,7 +81,8 @@ module Puppet
def retrieve
unless stat = @parent.stat(false)
- return :absent
+ @is = :absent
+ return
end
# Set our method appropriately, depending on links.
@@ -91,17 +92,15 @@ module Puppet
@method = :chown
end
- retval = stat.uid
+ self.is = stat.uid
# On OS X, files that are owned by -2 get returned as really
# large UIDs instead of negative ones. This isn't a Ruby bug,
# it's an OS X bug, since it shows up in perl, too.
- if retval > 120000
- self.warning "current state is silly: %s" % retval
- retval = :absent
+ if @is > 120000
+ self.warning "current state is silly: %s" % @is
+ @is = :absent
end
-
- return retval
end
# If we're not root, we can check the values but we cannot change
@@ -117,19 +116,19 @@ module Puppet
end
end
- def sync(value)
+ def sync
unless Process.uid == 0
unless defined? @@notifieduid
self.notice "Cannot manage ownership unless running as root"
#@parent.delete(self.name)
@@notifieduid = true
end
- return :nochange
+ return nil
end
user = nil
- unless user = self.validuser?(value)
- tmp = value
+ unless user = self.validuser?(self.should)
+ tmp = self.should
unless defined? @@usermissing
@@usermissing = {}
end
@@ -140,7 +139,7 @@ module Puppet
self.notice "user %s does not exist" % tmp
@@usermissing[tmp] = 1
end
- return :nochange
+ return nil
end
if @is == :absent
@@ -148,10 +147,10 @@ module Puppet
self.retrieve
if @is == :absent
self.debug "File does not exist; cannot set owner"
- return :nochange
+ return nil
end
if self.insync?
- return :nochange
+ return nil
end
#self.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
end
diff --git a/lib/puppet/type/port.rb b/lib/puppet/type/port.rb
deleted file mode 100755
index 3e73e625f..000000000
--- a/lib/puppet/type/port.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-require 'puppet/type/parsedtype'
-
-module Puppet
- newtype(:port, Puppet::Type::ParsedType) do
- @doc = "Installs and manages port entries. For most systems, these
- entries will just be in /etc/services, but some systems (notably OS X)
- will have different solutions."
-
- newstate(:protocols) do
- desc "The protocols the port uses. Valid values are *udp* and *tcp*.
- Most services have both protocols, but not all. If you want
- both protocols, you must specify that; Puppet replaces the
- current values, it does not merge with them. If you specify
- multiple protocols they must be as an array."
-
- def is=(value)
- case value
- when String
- @is = value.split(/\s+/)
- else
- @is = value
- end
- end
-
- def is
- @is
- end
-
- # We actually want to return the whole array here, not just the first
- # value.
- def should
- if defined? @should
- if @should[0] == :absent
- return :absent
- else
- return @should
- end
- else
- return nil
- end
- end
-
- validate do |value|
- valids = ["udp", "tcp", "ddp", :absent]
- unless valids.include? value
- raise Puppet::Error,
- "Protocols can be either 'udp' or 'tcp', not %s" % value
- end
- end
- end
-
- newstate(:number) do
- desc "The port number."
- end
-
- newstate(:description) do
- desc "The port description."
- isoptional
- end
-
- newstate(:alias) do
- desc "Any aliases the port might have. Multiple values must be
- specified as an array. Note that this state has the same name as
- one of the metaparams; using this state to set aliases will make
- those aliases available in your Puppet scripts and also on disk."
-
- isoptional
-
- # We actually want to return the whole array here, not just the first
- # value.
- def should
- if defined? @should
- if @should[0] == :absent
- return :absent
- else
- return @should
- end
- else
- return nil
- end
- end
-
- validate do |value|
- if value.is_a? String and value =~ /\s/
- raise Puppet::Error,
- "Aliases cannot have whitespace in them: %s" %
- value.inspect
- end
- end
-
- munge do |value|
- unless value == "absent" or value == :absent
- # Add the :alias metaparam in addition to the state
- @parent.newmetaparam(
- @parent.class.metaparamclass(:alias), value
- )
- end
- value
- end
- end
-
- newparam(:name) do
- desc "The port name."
-
- isnamevar
- end
- end
-end
-
-# $Id$
diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb
deleted file mode 100755
index e769199bf..000000000
--- a/lib/puppet/type/sshkey.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-module Puppet
- newtype(:sshkey, Puppet::Type::ParsedType) do
- @doc = "Installs and manages ssh host keys. At this point, this type
- only knows how to install keys into /etc/ssh/ssh_known_hosts, and
- it cannot manage user authorized keys yet."
-
- newstate(:type) do
- desc "The encryption type used. Probably ssh-dss or ssh-rsa."
- end
-
- newstate(:key) do
- desc "The key itself; generally a long string of hex digits."
- end
-
- # FIXME This should automagically check for aliases to the hosts, just
- # to see if we can automatically glean any aliases.
- newstate(:alias) do
- desc "Any alias the host might have. Multiple values must be
- specified as an array. Note that this state has the same name
- as one of the metaparams; using this state to set aliases will
- make those aliases available in your Puppet scripts."
-
- # We actually want to return the whole array here, not just the first
- # value.
- def should
- if defined? @should
- return @should
- else
- return nil
- end
- end
-
- validate do |value|
- if value =~ /\s/
- raise Puppet::Error, "Aliases cannot include whitespace"
- end
- if value =~ /,/
- raise Puppet::Error, "Aliases cannot include whitespace"
- end
- end
-
- # Make a puppet alias in addition.
- munge do |value|
- # Add the :alias metaparam in addition to the state
- @parent.newmetaparam(@parent.class.metaparamclass(:alias), value)
- value
- end
- end
-
- newparam(:name) do
- desc "The host name."
-
- isnamevar
- end
- end
-end
-
-# $Id$
diff --git a/lib/puppet/type/state.rb b/lib/puppet/type/state.rb
index e186c401d..de0cfeb00 100644
--- a/lib/puppet/type/state.rb
+++ b/lib/puppet/type/state.rb
@@ -8,11 +8,12 @@ require 'puppet/parameter'
module Puppet
class State < Puppet::Parameter
+ attr_accessor :is
+
# Because 'should' uses an array, we have a special method for handling
# it. We also want to keep copies of the original values, so that
# they can be retrieved and compared later when merging.
attr_reader :shouldorig
- attr_writer :is
class << self
attr_accessor :unmanaged
@@ -92,19 +93,11 @@ class State < Puppet::Parameter
def change_to_s
begin
if @is == :absent
- if self.name == :ensure
- return "created as '%s'" % [self.should_to_s]
- else
- return "defined '%s' as '%s'" %
- [self.name, self.should_to_s]
- end
+ return "defined '%s' as '%s'" %
+ [self.name, self.should_to_s]
elsif self.should == :absent or self.should == [:absent]
- if self.name == :ensure
- return "deleted from '%s'" % self.is_to_s
- else
- return "undefined %s from '%s'" %
- [self.name, self.is_to_s]
- end
+ return "undefined %s from '%s'" %
+ [self.name, self.is_to_s]
else
return "%s changed '%s' to '%s'" %
[self.name, self.is_to_s, self.should_to_s]
@@ -116,11 +109,6 @@ class State < Puppet::Parameter
[self.name, detail]
end
end
-
- # Just a simple wrapper method to sync our current 'should' value.
- def commit
- self.sync(self.should)
- end
# initialize our state
def initialize(hash)
@@ -179,9 +167,8 @@ class State < Puppet::Parameter
end
# Look for a matching value
- is = self.is
@should.each { |val|
- if is == val
+ if @is == val
return true
end
}
@@ -190,17 +177,12 @@ class State < Puppet::Parameter
return false
end
- # If the '@is' value is set, then return it, else retrieve it.
- def is
- @is || self.retrieve
- end
-
# because the @should and @is vars might be in weird formats,
# we need to set up a mechanism for pretty printing of the values
# default to just the values, but this way individual states can
# override these methods
def is_to_s
- self.is
+ @is
end
# Send a log message.
@@ -254,11 +236,17 @@ class State < Puppet::Parameter
# provider. In other words, if the state name is 'gid', we'll call
# 'provider.gid' to retrieve the current value.
def retrieve
- provider.send(self.class.name)
+ @is = provider.send(self.class.name)
end
# Call the method associated with a given value.
- def set(value)
+ def set
+ if self.insync?
+ self.log "already in sync"
+ return nil
+ end
+
+ value = self.should
method = "set_" + value.to_s
event = nil
if self.respond_to?(method)
@@ -288,18 +276,28 @@ class State < Puppet::Parameter
end
end
- if event == :nochange
- return :nochange
- end
-
if setevent = self.class.event(value)
return setevent
else
if event and event.is_a?(Symbol)
- return event
+ if event == :nochange
+ return nil
+ else
+ return event
+ end
else
- # StateChange will autogenerate an event.
- return nil
+ # Return the appropriate event.
+ event = case self.should
+ when :present: (@parent.class.name.to_s + "_created").intern
+ when :absent: (@parent.class.name.to_s + "_removed").intern
+ else
+ (@parent.class.name.to_s + "_changed").intern
+ end
+
+ #self.log "made event %s because 'should' is %s, 'is' is %s" %
+ # [event, self.should.inspect, self.is.inspect]
+
+ return event
end
end
end
@@ -349,20 +347,20 @@ class State < Puppet::Parameter
# The default 'sync' method only selects among a list of registered
# values.
- def sync(value = nil)
-
- unless value
- warnstamp :novalsynced, "No value passed to sync"
- value = self.should
+ def sync
+ if self.insync?
+ self.info "already in sync"
+ return nil
+ #else
+ #self.info "%s vs %s" % [self.is.inspect, self.should.inspect]
end
-
unless self.class.values
self.devfail "No values defined for %s" %
self.class.name
end
# Set ourselves to whatever our should value is.
- self.set(value || self.should)
+ self.set
end
def to_s
@@ -387,9 +385,15 @@ class State < Puppet::Parameter
@doc ||= "The basic state that the object should be in."
end
+ def self.inherited(sub)
+ # Add in the two states that everyone will have.
+ sub.class_eval do
+ end
+ end
+
def change_to_s
begin
- if self.is == :absent
+ if @is == :absent
return "created"
elsif self.should == :absent
return "removed"
@@ -412,9 +416,9 @@ class State < Puppet::Parameter
# @is values set. This seems to be the source of quite a few bugs,
# although they're mostly logging bugs, not functional ones.
if @parent.exists?
- return :present
+ @is = :present
else
- return :absent
+ @is = :absent
end
end
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index b0c3081e4..3a78d9669 100755
--- a/lib/puppet/type/user.rb
+++ b/lib/puppet/type/user.rb
@@ -50,7 +50,7 @@ module Puppet
def change_to_s
begin
- if self.is == :absent
+ if @is == :absent
return "created"
elsif self.should == :absent
return "removed"
@@ -69,11 +69,30 @@ module Puppet
def retrieve
if provider.exists?
- return :present
+ @is = :present
else
- return :absent
+ @is = :absent
end
end
+
+ # The default 'sync' method only selects among a list of registered
+ # values.
+ def sync
+ if self.insync?
+ self.info "already in sync"
+ return nil
+ #else
+ #self.info "%s vs %s" % [self.is.inspect, self.should.inspect]
+ end
+ unless self.class.values
+ self.devfail "No values defined for %s" %
+ self.class.name
+ end
+
+ # Set ourselves to whatever our should value is.
+ self.set
+ end
+
end
newstate(:uid) do
@@ -174,21 +193,24 @@ module Puppet
end
def is_to_s
- self.is.join(",")
+ @is.join(",")
end
# We need to override this because the groups need to
# be joined with commas
def should
+ unless defined? @is
+ retrieve
+ end
+
@should ||= []
if @parent[:membership] == :inclusive
@should.sort
else
- current = self.is
members = @should
- if current.is_a?(Array)
- members += current
+ if @is.is_a?(Array)
+ members += @is
end
members.uniq.sort
end
@@ -196,13 +218,9 @@ module Puppet
def retrieve
if tmp = provider.groups
- if tmp == :absent
- return tmp
- else
- return tmp.split(",")
- end
+ @is = tmp.split(",")
else
- return :absent
+ @is = :absent
end
end
@@ -210,13 +228,13 @@ module Puppet
unless defined? @should and @should
return false
end
- unless defined? self.is and self.is
+ unless defined? @is and @is
return false
end
- unless self.is.class == @should.class
+ unless @is.class == @should.class
return false
end
- return self.is.sort == @should.sort
+ return @is.sort == @should.sort
end
validate do |value|
@@ -225,8 +243,8 @@ module Puppet
end
end
- def sync(value)
- provider.groups = value.join(",")
+ def sync
+ provider.groups = self.should.join(",")
:user_changed
end
end
@@ -356,16 +374,27 @@ module Puppet
def retrieve
absent = false
- current = {}
states().each { |state|
- if current[:ensure] == :absent
- current[state.name] = :absent
+ if absent
+ state.is = :absent
else
- current[state.name] = state.retrieve
+ state.retrieve
end
- }
- return current
+ if state.name == :ensure and state.is == :absent
+ absent = true
+ next
+ end
+ }
+ #if provider.exists?
+ # super
+ #else
+ # # the user does not exist
+ # @states.each { |name, state|
+ # state.is = :absent
+ # }
+ # return
+ #end
end
end
end
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index 515a91c36..a818a77bf 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -512,15 +512,6 @@ module Util
return seconds
end
- def warnstamp(var, msg)
- $stampwarnings ||= {}
- $stampwarnings[self.class] ||= {}
- unless $stampwarnings[self.class][var]
- warning msg
- $stampwarnings[self.class][var] = true
- end
- end
-
module_function :memory
end
end