summaryrefslogtreecommitdiffstats
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
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
-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
-rw-r--r--test/data/types/mount/linux.fstab2
-rwxr-xr-xtest/providers/parsedcron.rb744
-rw-r--r--test/providers/parsedhost.rb242
-rwxr-xr-xtest/providers/parsedmount.rb220
-rwxr-xr-xtest/providers/parsedport.rb61
-rwxr-xr-xtest/providers/parsedsshkey.rb38
-rw-r--r--test/puppettest.rb57
-rwxr-xr-xtest/types/cron.rb2
-rw-r--r--test/types/file.rb14
-rwxr-xr-xtest/types/group.rb17
-rwxr-xr-xtest/types/host.rb103
-rwxr-xr-xtest/types/mount.rb272
-rw-r--r--test/types/package.rb2
-rwxr-xr-xtest/types/port.rb116
-rwxr-xr-xtest/types/sshkey.rb83
-rwxr-xr-xtest/types/user.rb2
53 files changed, 1800 insertions, 3325 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
diff --git a/test/data/types/mount/linux.fstab b/test/data/types/mount/linux.fstab
index 978103b69..06afe1242 100644
--- a/test/data/types/mount/linux.fstab
+++ b/test/data/types/mount/linux.fstab
@@ -4,7 +4,7 @@ LABEL=/boot /boot ext3 defaults 1 2
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /dev/shm tmpfs defaults 0 0
LABEL=/home /home ext3 defaults 1 2
-/home /homes auto bind 0 2
+/home /homes auto bind
proc /proc proc defaults 0 0
/dev/vg00/lv01 /spare ext3 defaults 1 2
sysfs /sys sysfs defaults 0 0
diff --git a/test/providers/parsedcron.rb b/test/providers/parsedcron.rb
deleted file mode 100755
index fafb0ee92..000000000
--- a/test/providers/parsedcron.rb
+++ /dev/null
@@ -1,744 +0,0 @@
-# Test cron job creation, modification, and destruction
-
-if __FILE__ == $0
- $:.unshift '..'
- $:.unshift '../lib'
- $puppetbase = "../.."
-end
-
-require 'puppettest'
-require 'puppet'
-require 'test/unit'
-require 'facter'
-
-class TestParsedCron < Test::Unit::TestCase
- include TestPuppet
- def setup
- super
- @provider = Puppet.type(:cron).provider(:parsed)
-
- @oldfiletype = @provider.filetype
- end
-
- def teardown
- Puppet::FileType.filetype(:ram).clear
- @provider.filetype = @oldfiletype
- super
- end
-
- def test_provider_existence
- assert(@provider, "Could not retrieve provider")
- end
-
- # Here we just create a fake cron type that answers to all of the methods
- # but does not modify our actual system.
- def mkfaketype
- @provider.filetype = Puppet::FileType.filetype(:ram)
- end
-
- def mkcronhash
- if defined? @hcount
- @hcount += 1
- else
- @hcount = 1
- end
-
- return {
- :name => "fakecron%s" % @hcount,
- :ip => "192.168.27.%s" % @hcount,
- :alias => ["alias%s" % @hcount]
- }
- end
-
- def mkcron
- hash = mkcronhash()
-
- fakemodel = fakemodel(:cron, hash[:name])
-
- cron = @provider.new(fakemodel)
-
- hash.each do |name, val|
- fakemodel[name] = val
- end
- assert(cron, "Could not create provider cron")
-
- return cron
- end
-
- # Back up the user's existing cron tab if they have one.
- def cronback
- tab = nil
- assert_nothing_raised {
- tab = Puppet.type(:cron).filetype.read(@me)
- }
-
- if $? == 0
- @currenttab = tab
- else
- @currenttab = nil
- end
- end
-
- # Restore the cron tab to its original form.
- def cronrestore
- assert_nothing_raised {
- if @currenttab
- @crontype.filetype.new(@me).write(@currenttab)
- else
- @crontype.filetype.new(@me).remove
- end
- }
- end
-
- # Create a cron job with all fields filled in.
- def mkcron(name)
- cron = nil
- assert_nothing_raised {
- cron = @crontype.create(
- :command => "date > %s/crontest%s" % [tmpdir(), name],
- :name => name,
- :user => @me,
- :minute => rand(59),
- :month => "1",
- :monthday => "1",
- :hour => "1"
- )
- }
-
- return cron
- end
-
- # Run the cron through its paces -- install it then remove it.
- def cyclecron(cron)
- obj = Puppet::Type::Cron.cronobj(@me)
-
- text = obj.read
- name = cron.name
- comp = newcomp(name, cron)
-
- assert_events([:cron_created], comp)
- cron.retrieve
-
- assert(cron.insync?, "Cron is not in sync")
-
- assert_events([], comp)
-
- curtext = obj.read
- text.split("\n").each do |line|
- assert(curtext.include?(line), "Missing '%s'" % line)
- end
- obj = Puppet::Type::Cron.cronobj(@me)
-
- cron[:ensure] = :absent
-
- assert_events([:cron_deleted], comp)
-
- cron.retrieve
-
- assert(cron.insync?, "Cron is not in sync")
- assert_events([], comp)
- end
-
- # A simple test to see if we can load the cron from disk.
- def test_load
- assert_nothing_raised {
- @crontype.retrieve(@me)
- }
- end
-
- # Test that a cron job turns out as expected, by creating one and generating
- # it directly
- def test_simple_to_cron
- cron = nil
- # make the cron
- name = "yaytest"
- assert_nothing_raised {
- cron = @crontype.create(
- :name => name,
- :command => "date > /dev/null",
- :user => @me
- )
- }
- str = nil
- # generate the text
- assert_nothing_raised {
- str = cron.to_record
- }
-
- assert_equal(str, "# Puppet Name: #{name}\n* * * * * date > /dev/null",
- "Cron did not generate correctly")
- end
-
- def test_simpleparsing
- @fakefiletype = Puppet::FileType.filetype(:ram)
- @crontype.filetype = @fakefiletype
-
- @crontype.retrieve(@me)
- obj = Puppet::Type::Cron.cronobj(@me)
-
- text = "5 1,2 * 1 0 /bin/echo funtest"
-
- assert_nothing_raised {
- @crontype.parse(@me, text)
- }
-
- @crontype.each do |obj|
- assert_equal(["5"], obj.is(:minute), "Minute was not parsed correctly")
- assert_equal(["1", "2"], obj.is(:hour), "Hour was not parsed correctly")
- assert_equal([:absent], obj.is(:monthday), "Monthday was not parsed correctly")
- assert_equal(["1"], obj.is(:month), "Month was not parsed correctly")
- assert_equal(["0"], obj.is(:weekday), "Weekday was not parsed correctly")
- assert_equal(["/bin/echo funtest"], obj.is(:command), "Command was not parsed correctly")
- end
- end
-
- # Test that changing any field results in the cron tab being rewritten.
- # it directly
- def test_any_field_changes
- cron = nil
- # make the cron
- name = "yaytest"
- assert_nothing_raised {
- cron = @crontype.create(
- :name => name,
- :command => "date > /dev/null",
- :month => "May",
- :user => @me
- )
- }
- assert(cron, "Cron did not get created")
- comp = newcomp(cron)
- assert_events([:cron_created], comp)
-
- assert_nothing_raised {
- cron[:month] = "June"
- }
-
- cron.retrieve
-
- assert_events([:cron_changed], comp)
- end
-
- # Test that a cron job with spaces at the end doesn't get rewritten
- def test_trailingspaces
- cron = nil
- # make the cron
- name = "yaytest"
- assert_nothing_raised {
- cron = @crontype.create(
- :name => name,
- :command => "date > /dev/null ",
- :month => "May",
- :user => @me
- )
- }
- comp = newcomp(cron)
-
- assert_events([:cron_created], comp, "did not create cron job")
- cron.retrieve
- assert_events([], comp, "cron job got rewritten")
- end
-
- # Test that comments are correctly retained
- def test_retain_comments
- str = "# this is a comment\n#and another comment\n"
- user = "fakeuser"
- @crontype.retrieve(@me)
- assert_nothing_raised {
- @crontype.parse(@me, str)
- }
-
- assert_nothing_raised {
- newstr = @crontype.tab(@me)
- assert(newstr.include?(str), "Comments were lost")
- }
- end
-
- # Test that a specified cron job will be matched against an existing job
- # with no name, as long as all fields match
- def test_matchcron
- str = "0,30 * * * * date\n"
-
- assert_nothing_raised {
- cron = @crontype.create(
- :name => "yaycron",
- :minute => [0, 30],
- :command => "date",
- :user => @me
- )
- }
-
- assert_nothing_raised {
- @crontype.parse(@me, str)
- }
-
- count = @crontype.inject(0) do |c, obj|
- c + 1
- end
-
- assert_equal(1, count, "Did not match cron job")
-
- modstr = "# Puppet Name: yaycron\n%s" % str
-
- assert_nothing_raised {
- newstr = @crontype.tab(@me)
- assert(newstr.include?(modstr),
- "Cron was not correctly matched")
- }
- end
-
- # Test adding a cron when there is currently no file.
- def test_mkcronwithnotab
- tab = @fakefiletype.new(@me)
- tab.remove
-
- @crontype.retrieve(@me)
- cron = mkcron("testwithnotab")
- cyclecron(cron)
- end
-
- def test_mkcronwithtab
- @crontype.retrieve(@me)
- obj = Puppet::Type::Cron.cronobj(@me)
- obj.write(
-"1 1 1 1 * date > %s/crontesting\n" % tstdir()
- )
-
- cron = mkcron("testwithtab")
- cyclecron(cron)
- end
-
- def test_makeandretrievecron
- tab = @fakefiletype.new(@me)
- tab.remove
-
- %w{storeandretrieve a-name another-name more_naming SomeName}.each do |name|
- cron = mkcron(name)
- comp = newcomp(name, cron)
- trans = assert_events([:cron_created], comp, name)
-
- cron = nil
-
- Puppet.type(:cron).retrieve(@me)
-
- assert(cron = Puppet.type(:cron)[name], "Could not retrieve named cron")
- assert_instance_of(Puppet.type(:cron), cron)
- end
- end
-
- # Do input validation testing on all of the parameters.
- def test_arguments
- values = {
- :monthday => {
- :valid => [ 1, 13, "1" ],
- :invalid => [ -1, 0, 32 ]
- },
- :weekday => {
- :valid => [ 0, 3, 6, "1", "tue", "wed",
- "Wed", "MOnday", "SaTurday" ],
- :invalid => [ -1, 7, "13", "tues", "teusday", "thurs" ]
- },
- :hour => {
- :valid => [ 0, 21, 23 ],
- :invalid => [ -1, 24 ]
- },
- :minute => {
- :valid => [ 0, 34, 59 ],
- :invalid => [ -1, 60 ]
- },
- :month => {
- :valid => [ 1, 11, 12, "mar", "March", "apr", "October", "DeCeMbEr" ],
- :invalid => [ -1, 0, 13, "marc", "sept" ]
- }
- }
-
- cron = mkcron("valtesting")
- values.each { |param, hash|
- # We have to test the valid ones first, because otherwise the
- # state will fail to create at all.
- [:valid, :invalid].each { |type|
- hash[type].each { |value|
- case type
- when :valid:
- assert_nothing_raised {
- cron[param] = value
- }
-
- if value.is_a?(Integer)
- assert_equal(value.to_s, cron.should(param),
- "Cron value was not set correctly")
- end
- when :invalid:
- assert_raise(Puppet::Error, "%s is incorrectly a valid %s" %
- [value, param]) {
- cron[param] = value
- }
- end
-
- if value.is_a?(Integer)
- value = value.to_s
- redo
- end
- }
- }
- }
- end
-
- # Test that we can read and write cron tabs
- def test_crontab
- Puppet.type(:cron).filetype = Puppet.type(:cron).defaulttype
- type = nil
- unless type = Puppet.type(:cron).filetype
- $stderr.puts "No crontab type; skipping test"
- end
-
- obj = nil
- assert_nothing_raised {
- obj = type.new(Process.uid)
- }
-
- txt = nil
- assert_nothing_raised {
- txt = obj.read
- }
-
- assert_nothing_raised {
- obj.write(txt)
- }
- end
-
- # Verify that comma-separated numbers are not resulting in rewrites
- def test_norewrite
- cron = nil
- assert_nothing_raised {
- cron = Puppet.type(:cron).create(
- :command => "/bin/date > /dev/null",
- :minute => [0, 30],
- :name => "crontest"
- )
- }
-
- assert_events([:cron_created], cron)
- cron.retrieve
- assert_events([], cron)
- end
-
- def test_fieldremoval
- cron = nil
- assert_nothing_raised {
- cron = Puppet.type(:cron).create(
- :command => "/bin/date > /dev/null",
- :minute => [0, 30],
- :name => "crontest"
- )
- }
-
- assert_events([:cron_created], cron)
-
- cron[:minute] = :absent
- assert_events([:cron_changed], cron)
- assert_nothing_raised {
- cron.retrieve
- }
- assert_equal(:absent, cron.is(:minute))
- end
-
- def test_listing
- @crontype.filetype = @oldfiletype
-
- crons = []
- assert_nothing_raised {
- Puppet::Type.type(:cron).list.each do |cron|
- crons << cron
- end
- }
-
- crons.each do |cron|
- assert(cron, "Did not receive a real cron object")
- assert_instance_of(String, cron[:user],
- "Cron user is not a string")
- end
- end
-
- def verify_failonnouser
- assert_raise(Puppet::Error) do
- @crontype.retrieve("nosuchuser")
- end
- end
-
- def test_names
- cron = mkcron("nametest")
-
- ["bad name", "bad.name"].each do |name|
- assert_raise(ArgumentError) do
- cron[:name] = name
- end
- end
-
- ["good-name", "good-name", "AGoodName"].each do |name|
- assert_nothing_raised do
- cron[:name] = name
- end
- end
- end
-
- # Make sure we don't puke on env settings
- def test_envsettings
- cron = mkcron("envtst")
-
- assert_apply(cron)
-
- obj = Puppet::Type::Cron.cronobj(@me)
-
- assert(obj)
-
- text = obj.read
-
- text = "SHELL = /path/to/some/thing\n" + text
-
- obj.write(text)
-
- assert_nothing_raised {
- cron.retrieve
- }
-
- cron[:command] = "/some/other/command"
-
- assert_apply(cron)
-
- assert(obj.read =~ /SHELL/, "lost env setting")
-
- env1 = "TEST = /bin/true"
- env2 = "YAY = fooness"
- assert_nothing_raised {
- cron[:environment] = [env1, env2]
- }
-
- assert_apply(cron)
- cron.retrieve
-
- vals = cron.is(:environment)
- assert(vals, "Did not get environment settings")
- assert(vals != :absent, "Env is incorrectly absent")
- assert_instance_of(Array, vals)
-
- assert(vals.include?(env1), "Missing first env setting")
- assert(vals.include?(env2), "Missing second env setting")
-
- end
-
- def test_divisionnumbers
- cron = mkcron("divtest")
- cron[:minute] = "*/5"
-
- assert_apply(cron)
-
- cron.retrieve
-
- assert_equal(["*/5"], cron.is(:minute))
- end
-
- def test_ranges
- cron = mkcron("rangetest")
- cron[:minute] = "2-4"
-
- assert_apply(cron)
-
- cron.retrieve
-
- assert_equal(["2-4"], cron.is(:minute))
- end
-
- def test_data
- @fakefiletype = Puppet::FileType.filetype(:ram)
- @crontype.filetype = @fakefiletype
-
- @crontype.retrieve(@me)
- obj = Puppet::Type::Cron.cronobj(@me)
-
- fakedata("data/types/cron").each do |file|
- names = []
- text = File.read(file)
- obj.write(File.read(file))
-
- @crontype.retrieve(@me)
-
- @crontype.each do |cron|
- names << cron.name
- end
-
- name = File.basename(file)
- cron = mkcron("filetest-#{name}")
-
- assert_apply(cron)
-
- @crontype.retrieve(@me)
-
- names.each do |name|
- assert(@crontype[name], "Could not retrieve %s" % name)
- end
-
- tablines = @crontype.tab(@me).split("\n")
-
- text.split("\n").each do |line|
- assert(tablines.include?(line),
- "Did not get %s back out" % line.inspect)
- end
- end
- end
-
- def test_value
- cron = mkcron("valuetesting")
-
- # First, test the normal states
- [:minute, :hour, :month].each do |param|
- state = cron.state(param)
-
- assert(state, "Did not get %s state" % param)
-
- assert_nothing_raised {
- state.should = :absent
- state.is = :absent
- }
-
- # Make sure our minute default is 0, not *
- val = if param == :minute
- "*" # the "0" thing is disabled for now
- else
- "*"
- end
- assert_equal(val, cron.value(param))
-
- # Make sure we correctly get the "is" value if that's all there is
- cron.is = [param, "1"]
- assert_equal("1", cron.value(param))
-
- # Make sure arrays work, too
- cron.is = [param, ["1"]]
- assert_equal("1", cron.value(param))
-
- # Make sure values get comma-joined
- cron.is = [param, ["2", "3"]]
- assert_equal("2,3", cron.value(param))
-
- # Make sure "should" values work, too
- cron[param] = "4"
- assert_equal("4", cron.value(param))
-
- cron[param] = ["4"]
- assert_equal("4", cron.value(param))
-
- cron[param] = ["4", "5"]
- assert_equal("4,5", cron.value(param))
-
- cron.is = [param, :absent]
- assert_equal("4,5", cron.value(param))
- end
-
- # Now make sure that :command works correctly
- state = cron.state(:command)
-
- assert_nothing_raised {
- state.should = :absent
- state.is = :absent
- }
-
- assert(state, "Did not get command state")
- assert_raise(Puppet::DevError) do
- cron.value(:command)
- end
-
- param = :command
- # Make sure we correctly get the "is" value if that's all there is
- cron.is = [param, "1"]
- assert_equal("1", cron.value(param))
-
- # Make sure arrays work, too
- cron.is = [param, ["1"]]
- assert_equal("1", cron.value(param))
-
- # Make sure values are not comma-joined
- cron.is = [param, ["2", "3"]]
- assert_equal("2", cron.value(param))
-
- # Make sure "should" values work, too
- cron[param] = "4"
- assert_equal("4", cron.value(param))
-
- cron[param] = ["4"]
- assert_equal("4", cron.value(param))
-
- cron[param] = ["4", "5"]
- assert_equal("4", cron.value(param))
-
- cron.is = [param, :absent]
- assert_equal("4", cron.value(param))
- end
-
- # Make sure we can successfully list all cron jobs on all users
- def test_cron_listing
- crons = []
- %w{fake1 fake2 fake3 fake4 fake5}.each do |user|
- crons << @crontype.create(
- :name => "#{user}-1",
- :command => "/usr/bin/#{user}",
- :minute => "0",
- :user => user,
- :hour => user.sub("fake",'')
- )
-
- crons << @crontype.create(
- :name => "#{user}-2",
- :command => "/usr/sbin/#{user}",
- :minute => "0",
- :user => user,
- :weekday => user.sub("fake",'')
- )
-
- assert_apply(*crons)
- end
-
- list = @crontype.list.collect { |c| c.name }
-
- crons.each do |cron|
- assert(list.include?(cron.name), "Did not match cron %s" % name)
- end
- end
-
- # Make sure we can create a cron in an empty tab
- def test_mkcron_if_empty
- @crontype.filetype = @oldfiletype
-
- @crontype.retrieve(@me)
-
- # Backup our tab
- text = @crontype.tabobj(@me).read
-
- cleanup do
- if text == ""
- @crontype.tabobj(@me).remove
- else
- @crontype.tabobj(@me).write(text)
- end
- end
-
- # Now get rid of it
- @crontype.tabobj(@me).remove
- @crontype.clear
-
- cron = mkcron("emptycron")
-
- assert_apply(cron)
-
- # Clear the type, but don't clear the filetype
- @crontype.clear
-
- # Get the stuff again
- @crontype.retrieve(@me)
-
- assert(@crontype["emptycron"],
- "Did not retrieve cron")
- end
-end
-
-# $Id$
diff --git a/test/providers/parsedhost.rb b/test/providers/parsedhost.rb
deleted file mode 100644
index bb122129a..000000000
--- a/test/providers/parsedhost.rb
+++ /dev/null
@@ -1,242 +0,0 @@
-if __FILE__ == $0
- $:.unshift '..'
- $:.unshift '../../lib'
- $puppetbase = "../.."
-end
-
-require 'etc'
-require 'puppet/type'
-require 'puppettest'
-require 'test/unit'
-
-class TestParsedHostProvider < Test::Unit::TestCase
- include TestPuppet
-
- def setup
- super
- @provider = Puppet.type(:host).provider(:parsed)
-
- @oldfiletype = @provider.filetype
- end
-
- def teardown
- Puppet::FileType.filetype(:ram).clear
- @provider.filetype = @oldfiletype
- super
- end
-
- def test_provider_existence
- assert(@provider, "Could not retrieve provider")
- end
-
- # Here we just create a fake host type that answers to all of the methods
- # but does not modify our actual system.
- def mkfaketype
- @provider.filetype = Puppet::FileType.filetype(:ram)
- end
-
- def mkhosthash
- if defined? @hcount
- @hcount += 1
- else
- @hcount = 1
- end
-
- return {
- :name => "fakehost%s" % @hcount,
- :ip => "192.168.27.%s" % @hcount,
- :alias => ["alias%s" % @hcount]
- }
- end
-
- def mkhost
- hash = mkhosthash()
-
- fakemodel = fakemodel(:host, hash[:name])
-
- host = @provider.new(fakemodel)
-
- hash.each do |name, val|
- fakemodel[name] = val
- end
- assert(host, "Could not create provider host")
-
- return host
- end
-
- # Make sure we convert both directlys correctly using a simple host.
- def test_basic_isomorphism
- hash = {:name => "myhost", :ip => "192.168.43.56", :alias => %w{another host}}
-
- str = nil
- assert_nothing_raised do
- str = @provider.to_record(hash)
- end
-
- assert_equal("192.168.43.56\tmyhost\tanother\thost", str)
-
- newhash = nil
- assert_nothing_raised do
- newhash = @provider.parse(str).shift
- end
-
- assert_equal(hash, newhash)
- end
-
- # Make sure parsing gets comments, blanks, and hosts
- def test_blanks_and_comments
- mkfaketype()
- text = %{# comment one
-
-192.168.43.56\tmyhost\tanother\thost
-
-# another comment
-192.168.43.57\tanotherhost
-}
-
- instances = nil
- assert_nothing_raised do
- instances = @provider.parse(text)
- end
-
- assert_equal([
- "# comment one",
- "",
- {:name => "myhost", :ip => "192.168.43.56", :alias => %w{another host}},
- " ",
- "# another comment",
- {:name => "anotherhost", :ip => "192.168.43.57"}
- ], instances)
-
- assert_nothing_raised do
- @provider.store(instances)
- end
- newtext = nil
- assert_nothing_raised do
- newtext = @provider.fileobj.read
- end
-
- assert_equal(text, newtext)
- end
-
- def test_empty_and_absent_hashes_are_not_written
- mkfaketype()
-
- instances = [
- {:name => "myhost", :ip => "192.168.43.56", :alias => %w{another host}},
- {},
- {:ensure => :absent, :name => "anotherhost", :ip => "192.168.43.57"}
- ]
-
- assert_nothing_raised do
- newtext = @provider.store(instances)
- end
- newtext = nil
- assert_nothing_raised do
- newtext = @provider.fileobj.read
- end
- text = "192.168.43.56\tmyhost\tanother\thost\n"
-
- assert_equal(text, newtext)
- end
-
- def test_simplehost
- mkfaketype
- # Start out with no content.
- assert_nothing_raised {
- assert_equal([], @provider.retrieve)
- }
-
- # Now create a provider
- host = nil
- assert_nothing_raised {
- host = mkhost
- }
-
- # Make sure we're still empty
- assert_nothing_raised {
- assert_equal([], @provider.retrieve)
- }
-
- hash = host.model.to_hash
-
- # Try storing it
- assert_nothing_raised do
- host.store(hash)
- end
-
- # Make sure we get the host back
- assert_nothing_raised {
- assert_equal([hash], @provider.retrieve)
- }
-
- # Remove a single field and make sure it gets tossed
- hash.delete(:alias)
-
- assert_nothing_raised {
- host.store(hash)
- assert_equal([hash], @provider.retrieve)
- }
-
- # Make sure it throws up if we remove a required field
- hash.delete(:ip)
-
- assert_raise(ArgumentError) {
- host.store(hash)
- }
-
- # Now remove the whole object
- assert_nothing_raised {
- host.store({})
- assert_equal([], @provider.retrieve)
- }
- end
-
- # Parse our sample data and make sure we regenerate it correctly.
- def test_hostsparse
- fakedata("data/types/hosts").each do |file| fakedataparse(file) end
- end
-
- # Make sure we can modify the file elsewhere and those modifications will
- # get taken into account.
- def test_modifyingfile
- hostfile = tempfile()
- @provider.path = hostfile
-
- hosts = []
- 3.times {
- h = mkhost()
- hosts << h
- }
-
- hosts.each do |host|
- host.store
- end
-
- newhost = mkhost()
- hosts << newhost
-
- # Now store our new host
- newhost.store()
-
- # Verify we can retrieve that info
- assert_nothing_raised("Could not retrieve after second write") {
- newhost.hash
- }
-
- text = @provider.fileobj.read
-
- instances = @provider.retrieve
-
- # And verify that we have data for everything
- hosts.each { |host|
- name = host.model[:name]
- assert(text.include?(name), "Host %s is not in file" % name)
- hash = host.hash
- assert(! hash.empty?, "Could not find host %s" % name)
- assert(hash[:ip], "Could not find ip for host %s" % name)
- }
- end
-end
-
-# $Id$
diff --git a/test/providers/parsedmount.rb b/test/providers/parsedmount.rb
deleted file mode 100755
index a1630f7be..000000000
--- a/test/providers/parsedmount.rb
+++ /dev/null
@@ -1,220 +0,0 @@
-if __FILE__ == $0
- $:.unshift '..'
- $:.unshift '../../lib'
- $puppetbase = "../.."
-end
-
-require 'puppettest'
-require 'puppet'
-require 'test/unit'
-require 'facter'
-
-class TestParsedMounts < Test::Unit::TestCase
- include TestPuppet
-
- def setup
- super
- @provider = Puppet.type(:mount).provider(:parsed)
-
- @oldfiletype = @provider.filetype
- end
-
- def teardown
- Puppet::FileType.filetype(:ram).clear
- @provider.filetype = @oldfiletype
- super
- end
-
- def mkmountargs
- mount = nil
-
- if defined? @pcount
- @pcount += 1
- else
- @pcount = 1
- end
- args = {
- :path => "/fspuppet%s" % @pcount,
- :device => "/dev/dsk%s" % @pcount,
- }
-
- @provider.fields.each do |field|
- unless args.include? field
- args[field] = "fake%s" % @pcount
- end
- end
-
- return args
- end
-
- def mkmount
- hash = mkmountargs()
- #hash[:provider] = @provider.name
-
- fakemodel = fakemodel(:mount, hash[:name])
-
- mount = @provider.new(fakemodel)
- #mount = Puppet.type(:mount).create(hash)
-
- hash.each do |name, val|
- fakemodel[name] = val
- end
- assert(mount, "Could not create provider mount")
-
- return mount
- end
-
- # Here we just create a fake host type that answers to all of the methods
- # but does not modify our actual system.
- def mkfaketype
- @provider.filetype = Puppet::FileType.filetype(:ram)
- end
-
- def test_simplemount
- mkfaketype
- assert_nothing_raised {
- assert_equal([], @provider.retrieve)
- }
-
- # Now create a provider
- mount = nil
- assert_nothing_raised {
- mount = mkmount
- }
-
- # Make sure we're still empty
- assert_nothing_raised {
- assert_equal([], @provider.retrieve)
- }
-
- hash = mount.model.to_hash
-
- if hash.has_key? :name
- hash.delete :name
- end
-
- # Try storing it
- assert_nothing_raised do
- mount.store(hash)
- end
-
- # Make sure we get the mount back
- assert_nothing_raised {
- assert_equal([hash], @provider.retrieve)
- }
-
- # Now remove the whole object
- assert_nothing_raised {
- mount.store({})
- assert_equal([], @provider.retrieve)
- }
- end
-
- unless Facter["operatingsystem"].value == "Darwin"
- def test_mountsparse
- fakedataparse(fake_fstab) do
- # Now just make we've got some mounts we know will be there
- hashes = @provider.retrieve.find_all { |i| i.is_a? Hash }
- assert(hashes.length > 0, "Did not create any hashes")
- root = hashes.find { |i| i[:path] == "/" }
- assert(root, "Could not retrieve root mount")
- end
- end
-
- def test_rootfs
- fs = nil
- @provider.path = fake_fstab()
- fakemodel = fakemodel(:mount, "/")
- mount = @provider.new(fakemodel)
- mount.model[:path] = "/"
- assert(mount.hash, "Could not retrieve root fs")
-
- assert_nothing_raised {
- assert(mount.mounted?, "Root is considered not mounted")
- }
- end
- end
-
- if Process.uid == 0
- def test_mountfs
- fs = nil
- case Facter["hostname"].value
- when "culain": fs = "/ubuntu"
- when "atalanta": fs = "/mnt"
- when "figurehead": fs = "/cg4/net/depts"
- else
- $stderr.puts "No mount for mount testing; skipping"
- return
- end
-
- oldtext = @provider.fileobj.read
-
- ftype = @provider.filetype
-
- # Make sure the original gets reinstalled.
- if ftype == Puppet::FileType.filetype(:netinfo)
- cleanup do
- IO.popen("niload -r /mounts .", "w") do |file|
- file.puts oldtext
- end
- end
- else
- cleanup do
- @provider.fileobj.write(oldtext)
- end
- end
-
- fakemodel = fakemodel(:mount, "/")
- obj = @provider.new(fakemodel)
- obj.model[:path] = fs
-
- current = nil
-
- assert_nothing_raised {
- current = obj.mounted?
- }
-
- if current
- # Make sure the original gets reinstalled.
- cleanup do
- unless obj.mounted?
- obj.mount
- end
- end
- end
-
- unless current
- assert_nothing_raised {
- obj.mount
- }
- end
-
- assert_nothing_raised {
- obj.unmount
- }
- assert(! obj.mounted?, "FS still mounted")
- assert_nothing_raised {
- obj.mount
- }
- assert(obj.mounted?, "FS not mounted")
-
- end
- end
-
- def fake_fstab
- os = Facter['operatingsystem']
- if os == "Solaris"
- name = "solaris.fstab"
- elsif os == "FreeBSD"
- name = "freebsd.fstab"
- else
- # Catchall for other fstabs
- name = "linux.fstab"
- end
- oldpath = @provider.path
- cleanup do @provider.path = oldpath end
- return fakefile(File::join("data/types/mount", name))
- end
-end
-
-# $Id$
diff --git a/test/providers/parsedport.rb b/test/providers/parsedport.rb
deleted file mode 100755
index 51901f7f4..000000000
--- a/test/providers/parsedport.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# Test host job creation, modification, and destruction
-
-if __FILE__ == $0
- $:.unshift '..'
- $:.unshift '../../lib'
- $puppetbase = "../.."
-end
-
-require 'puppettest'
-require 'puppet'
-require 'puppet/type/parsedtype/port'
-require 'test/unit'
-require 'facter'
-
-class TestParsedPort < Test::Unit::TestCase
- include TestPuppet
-
- def setup
- super
- @provider = Puppet.type(:port).provider(:parsed)
-
- @oldfiletype = @provider.filetype
- end
-
- def teardown
- Puppet::FileType.filetype(:ram).clear
- @provider.filetype = @oldfiletype
- super
- end
-
- # Parse our sample data and make sure we regenerate it correctly.
- def test_portsparse
- fakedata("data/types/ports").each do |file|
- @provider.path = file
- instances = nil
- assert_nothing_raised {
- instances = @provider.retrieve
- }
-
- text = @provider.fileobj.read.gsub(/\s+/, ' ')
- text.gsub!(/ #.+$/, '')
-
- dest = tempfile()
- @provider.path = dest
-
- # Now write it back out
- assert_nothing_raised {
- @provider.store(instances)
- }
-
- newtext = @provider.fileobj.read.gsub(/\s+/, ' ')
-
- newtext.gsub!(/ #.+$/, '')
-
- # Don't worry about difference in whitespace
- assert_equal(text.gsub(/\s+/, ' '), newtext.gsub(/\s+/, ' '))
- end
- end
-end
-
-# $Id$
diff --git a/test/providers/parsedsshkey.rb b/test/providers/parsedsshkey.rb
deleted file mode 100755
index 7f21a58b4..000000000
--- a/test/providers/parsedsshkey.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# Test key job creation, modification, and destruction
-
-if __FILE__ == $0
- $:.unshift '..'
- $:.unshift '../../lib'
- $puppetbase = "../.."
-end
-
-require 'puppettest'
-require 'puppet'
-require 'puppet/type/parsedtype/sshkey'
-require 'test/unit'
-require 'facter'
-
-class TestParsedSSHKey < Test::Unit::TestCase
- include TestPuppet
-
- def setup
- super
- @provider = Puppet.type(:sshkey).provider(:parsed)
-
- @oldfiletype = @provider.filetype
- end
-
- def teardown
- Puppet::FileType.filetype(:ram).clear
- @provider.filetype = @oldfiletype
- super
- end
-
- def test_keysparse
- fakedata("data/types/sshkey").each { |file|
- fakedataparse(file)
- }
- end
-end
-
-# $Id$
diff --git a/test/puppettest.rb b/test/puppettest.rb
index 2506f9fc3..f094045cd 100644
--- a/test/puppettest.rb
+++ b/test/puppettest.rb
@@ -35,10 +35,6 @@ module TestPuppet
def name
self[:name]
end
-
- def to_hash
- self
- end
end
class FakeProvider
@@ -80,33 +76,6 @@ module TestPuppet
def initialize(model)
@model = model
end
-
- # Called in Type#remove
- def remove(var = true)
- end
- end
-
- class FakeParsedProvider < FakeProvider
- def hash
- ret = {}
- instance_variables.each do |v|
- v = v.sub("@", '')
- if val = self.send(v)
- ret[v.intern] = val
- end
- end
-
- return ret
- end
-
- def store(hash)
- hash.each do |n, v|
- method = n.to_s + "="
- if respond_to? method
- send(method, v)
- end
- end
- end
end
@@fakemodels = {}
@@ -467,32 +436,6 @@ module TestPuppet
return file
end
- # Run an isomorphism test on our parsing process.
- def fakedataparse(file)
- @provider.path = file
- instances = nil
- assert_nothing_raised {
- instances = @provider.retrieve
- }
-
- text = @provider.fileobj.read
-
- yield if block_given?
-
- dest = tempfile()
- @provider.path = dest
-
- # Now write it back out
- assert_nothing_raised {
- @provider.store(instances)
- }
-
- newtext = @provider.fileobj.read
-
- # Don't worry about difference in whitespace
- assert_equal(text.gsub(/\s+/, ' '), newtext.gsub(/\s+/, ' '))
- end
-
# wrap how to retrieve the masked mode
def filemode(file)
File.stat(file).mode & 007777
diff --git a/test/types/cron.rb b/test/types/cron.rb
index 94e490e40..caada9f91 100755
--- a/test/types/cron.rb
+++ b/test/types/cron.rb
@@ -97,7 +97,7 @@ class TestCron < Test::Unit::TestCase
cron[:ensure] = :absent
- assert_events([:cron_deleted], comp)
+ assert_events([:cron_removed], comp)
cron.retrieve
diff --git a/test/types/file.rb b/test/types/file.rb
index 194d00958..3dc296cc0 100644
--- a/test/types/file.rb
+++ b/test/types/file.rb
@@ -704,6 +704,8 @@ class TestFile < Test::Unit::TestCase
assert_events([:file_created], obj)
+ obj.retrieve
+
assert(obj.insync?, "Object is not in sync")
text = File.read(file)
@@ -793,17 +795,18 @@ class TestFile < Test::Unit::TestCase
dest = tempfile()
file = nil
- str = "some content, ok?"
assert_nothing_raised {
file = Puppet.type(:file).create(
:name => dest,
:ensure => "file",
- :content => str
+ :content => "this is some content, yo"
)
}
+ file.retrieve
+
assert_events([:file_created], file)
- assert_equal(str, File.read(dest))
+ file.retrieve
assert_events([], file)
assert_events([], file)
end
@@ -1197,7 +1200,7 @@ class TestFile < Test::Unit::TestCase
}
# First run through without :force
- assert_events([], file, "Link replaced directory without force enabled")
+ assert_events([], file)
assert(FileTest.directory?(link), "Link replaced dir without force")
@@ -1373,12 +1376,11 @@ class TestFile < Test::Unit::TestCase
lfobj = Puppet::Type.newfile(:path => localfile, :content => "rahtest")
- assert(! lfobj.implicit?, "object incorrectly implicit")
-
destobj = Puppet::Type.newfile(:path => destdir,
:source => sourcedir,
:recurse => true)
+
assert_apply(lfobj, destobj)
assert(FileTest.exists?(dsourcefile), "File did not get copied")
diff --git a/test/types/group.rb b/test/types/group.rb
index 2b47f14d4..508b8436c 100755
--- a/test/types/group.rb
+++ b/test/types/group.rb
@@ -18,9 +18,6 @@ class TestGroup < Test::Unit::TestCase
def create
@ensure = :present
-
- # Just set a fake gid
- self.gid = 10
end
def delete
@@ -79,7 +76,7 @@ class TestGroup < Test::Unit::TestCase
assert_events([:group_created], comp)
assert_equal(:present, group.provider.ensure, "Group is absent")
group[:ensure] = :absent
- trans = assert_events([:group_deleted], comp)
+ trans = assert_events([:group_removed], comp)
assert_equal(:absent, group.provider.ensure, "Group is present")
assert_rollback_events(trans, [:group_created], "group")
@@ -89,6 +86,7 @@ class TestGroup < Test::Unit::TestCase
# This is a bit odd, since we're not actually doing anything on the machine.
# Just make sure we can set the gid and that it will work correctly.
def attrtest_gid(group)
+
# Check the validation.
assert_nothing_raised {
group[:gid] = "15"
@@ -98,8 +96,7 @@ class TestGroup < Test::Unit::TestCase
"Did not convert gid to number")
comp = newcomp(group)
-
- trans = assert_events([:group_changed], comp, "group")
+ trans = assert_events([:group_modified], comp, "group")
assert_equal(15, group.provider.gid, "GID was not changed")
assert_nothing_raised {
@@ -110,12 +107,12 @@ class TestGroup < Test::Unit::TestCase
"Did not keep gid as number")
# Now switch to 16
- trans = assert_events([:group_changed], comp, "group")
+ trans = assert_events([:group_modified], comp, "group")
assert_equal(16, group.provider.gid, "GID was not changed")
# And then rollback
- assert_rollback_events(trans, [:group_changed], "group")
- assert_equal(15, group.provider.gid, "GID was not reverted")
+ assert_rollback_events(trans, [:group_modified], "group")
+ assert_equal(15, group.provider.gid, "GID was not changed")
end
def test_owngroups
@@ -170,7 +167,7 @@ class TestGroup < Test::Unit::TestCase
end
}
- assert_rollback_events(trans, [:group_deleted], "group")
+ assert_rollback_events(trans, [:group_removed], "group")
assert(! gobj.provider.exists?,
"Did not delete group")
diff --git a/test/types/host.rb b/test/types/host.rb
index 54596aa7f..8af9e3e4a 100755
--- a/test/types/host.rb
+++ b/test/types/host.rb
@@ -13,25 +13,24 @@ require 'facter'
class TestHost < Test::Unit::TestCase
include TestPuppet
-
def setup
super
+ # god i'm lazy
@hosttype = Puppet.type(:host)
+ @oldhosttype = @hosttype.filetype
+ end
- @provider = @hosttype.defaultprovider
-
- # Make sure they aren't using something funky like netinfo
- unless @provider.name == :parsed
- @hosttype.defaultprovider = @hosttype.provider(:parsed)
- end
-
- cleanup do @hosttype.defaultprovider = nil end
+ def teardown
+ Puppet::FileType.filetype(:ram).clear
+ @hosttype.filetype = @oldhosttype
+ Puppet.type(:file).clear
+ super
+ end
- oldpath = @provider.path
- cleanup do
- @provider.path = oldpath
- end
- @provider.path = tempfile()
+ # Here we just create a fake host type that answers to all of the methods
+ # but does not modify our actual system.
+ def mkfaketype
+ @hosttype.filetype = Puppet::FileType.filetype(:ram)
end
def mkhost
@@ -53,16 +52,10 @@ class TestHost < Test::Unit::TestCase
end
def test_simplehost
+ mkfaketype
host = nil
assert_nothing_raised {
- Puppet.type(:host).defaultprovider.retrieve
-
- count = 0
- @hosttype.each do |h|
- count += 1
- end
-
- assert_equal(0, count, "Found hosts in empty file somehow")
+ assert_nil(Puppet.type(:host).retrieve)
}
assert_nothing_raised {
@@ -72,14 +65,49 @@ class TestHost < Test::Unit::TestCase
)
}
- assert_apply(host)
+ assert_nothing_raised {
+ Puppet.type(:host).store
+ }
+
+ assert_nothing_raised {
+ assert(
+ Puppet.type(:host).to_file.include?(
+ Puppet.type(:host).fileobj.read
+ ),
+ "File does not include all of our objects"
+ )
+ }
+ end
+
+ def test_hostsparse
+ fakedata("data/types/hosts").each { |file|
+ @hosttype.path = file
+ Puppet.info "Parsing %s" % file
+ assert_nothing_raised {
+ Puppet.type(:host).retrieve
+ }
+
+ text = Puppet.type(:host).fileobj.read
- assert_nothing_raised { host.retrieve }
+ dest = tempfile()
+ @hosttype.path = dest
- assert_equal(:present, host.is(:ensure))
+ # Now write it back out
+ assert_nothing_raised {
+ Puppet.type(:host).store
+ }
+
+ newtext = Puppet.type(:host).fileobj.read
+
+ # Don't worry about difference in whitespace
+ assert_equal(text.gsub(/\s+/, ' '), newtext.gsub(/\s+/, ' '))
+
+ @hosttype.clear
+ }
end
def test_moddinghost
+ mkfaketype
host = mkhost()
assert_events([:host_created], host)
@@ -117,33 +145,34 @@ class TestHost < Test::Unit::TestCase
end
def test_removal
+ mkfaketype
host = mkhost()
assert_nothing_raised {
host[:ensure] = :present
}
assert_events([:host_created], host)
- assert(host.exists?, "Host is not considered in sync")
-
- assert_equal(:present, host.is(:ensure))
-
+ host.retrieve
+ assert(host.insync?)
assert_nothing_raised {
host[:ensure] = :absent
}
- assert_events([:host_deleted], host)
-
- text = host.provider.class.fileobj.read
- assert(! text.include?(host[:name]), "Host is still in text")
+ assert_events([:host_removed], host)
host.retrieve
assert_events([], host)
end
def test_modifyingfile
+ hostfile = tempfile()
+ Puppet.type(:host).path = hostfile
+
hosts = []
names = []
3.times {
h = mkhost()
+ #h[:ensure] = :present
+ #h.retrieve
hosts << h
names << h.name
}
@@ -151,18 +180,20 @@ class TestHost < Test::Unit::TestCase
hosts.clear
Puppet.type(:host).clear
newhost = mkhost()
+ #newhost[:ensure] = :present
names << newhost.name
assert_apply(newhost)
+ Puppet.type(:host).clear
# Verify we can retrieve that info
assert_nothing_raised("Could not retrieve after second write") {
newhost.retrieve
}
- text = newhost.provider.class.fileobj.read
-
# And verify that we have data for everything
names.each { |name|
- assert(text.include?(name), "Host is not in file")
+ host = Puppet.type(:host)[name]
+ assert(host)
+ assert(host[:ip])
}
end
end
diff --git a/test/types/mount.rb b/test/types/mount.rb
index c7bd378a9..70170289e 100755
--- a/test/types/mount.rb
+++ b/test/types/mount.rb
@@ -8,63 +8,40 @@ end
require 'puppettest'
require 'puppet'
+require 'puppet/type/parsedtype/mount'
require 'test/unit'
+require 'facter'
class TestMounts < Test::Unit::TestCase
include TestPuppet
-
- p = Puppet::Type.type(:mount).provide :fake, :parent => TestPuppet::FakeParsedProvider do
- @name = :fake
- apimethods :ensure
-
- attr_accessor :mounted
-
- def create
- @ensure = :present
- end
-
- def delete
- @ensure = :absent
- @mounted = false
- end
-
- def exists?
- if defined? @ensure and @ensure == :present
- true
- else
- false
- end
- end
-
- def mounted?
- self.mounted
- end
-
- def mount
- self.mounted = true
- end
-
- def unmount
- self.mounted = false
- end
- end
-
- FakeMountProvider = p
-
- @@fakeproviders[:mount] = p
-
def setup
super
- @realprovider = Puppet::Type.type(:mount).defaultprovider
- Puppet::Type.type(:mount).defaultprovider = FakeMountProvider
+ @mounttype = Puppet.type(:mount)
+ @oldfiletype = @mounttype.filetype
end
def teardown
- Puppet.type(:mount).clear
- Puppet::Type.type(:mount).defaultprovider = nil
+ @mounttype.filetype = @oldfiletype
+ Puppet.type(:file).clear
super
end
+ # Here we just create a fake host type that answers to all of the methods
+ # but does not modify our actual system.
+ def mkfaketype
+ pfile = tempfile()
+ old = @mounttype.filetype
+ @mounttype.filetype = Puppet::FileType.filetype(:ram)
+
+ cleanup do
+ @mounttype.filetype = old
+ @mounttype.fileobj = nil
+ end
+
+ # Reset this, just in case
+ @mounttype.fileobj = nil
+ end
+
def mkmount
mount = nil
@@ -78,7 +55,7 @@ class TestMounts < Test::Unit::TestCase
:device => "/dev/dsk%s" % @pcount,
}
- @realprovider.fields.each do |field|
+ Puppet.type(:mount).fields.each do |field|
unless args.include? field
args[field] = "fake%s" % @pcount
end
@@ -92,47 +69,178 @@ class TestMounts < Test::Unit::TestCase
end
def test_simplemount
- mount = nil
- oldprv = Puppet.type(:mount).defaultprovider
- Puppet.type(:mount).defaultprovider = nil
+ mkfaketype
+ host = nil
assert_nothing_raised {
- Puppet.type(:mount).defaultprovider.retrieve
+ assert_nil(Puppet.type(:mount).retrieve)
+ }
- count = 0
- Puppet.type(:mount).each do |h|
- count += 1
- end
+ mount = mkmount
- assert_equal(0, count, "Found mounts in empty file somehow")
+ assert_nothing_raised {
+ Puppet.type(:mount).store
}
- Puppet.type(:mount).defaultprovider = oldprv
- mount = mkmount
+ assert_nothing_raised {
+ assert(
+ Puppet.type(:mount).to_file.include?(
+ Puppet.type(:mount).fileobj.read
+ ),
+ "File does not include all of our objects"
+ )
+ }
+ end
+
+ unless Facter["operatingsystem"].value == "Darwin"
+ def test_mountsparse
+ use_fake_fstab
+ assert_nothing_raised {
+ @mounttype.retrieve
+ }
+
+ # Now just make we've got some mounts we know will be there
+ root = @mounttype["/"]
+ assert(root, "Could not retrieve root mount")
+ end
+
+ def test_rootfs
+ fs = nil
+ use_fake_fstab
+ assert_nothing_raised {
+ Puppet.type(:mount).retrieve
+ }
+
+ assert_nothing_raised {
+ fs = Puppet.type(:mount)["/"]
+ }
+ assert(fs, "Could not retrieve root fs")
+
+ assert_nothing_raised {
+ assert(fs.mounted?, "Root is considered not mounted")
+ }
+ end
+ end
+
+ # Make sure it reads and writes correctly.
+ def test_readwrite
+ use_fake_fstab
+ assert_nothing_raised {
+ Puppet::Type.type(:mount).retrieve
+ }
+
+ oldtype = Puppet::Type.type(:mount).filetype
+
+ # Now switch to storing in ram
+ mkfaketype
+
+ fs = mkmount
- assert_apply(mount)
+ assert(Puppet::Type.type(:mount).filetype != oldtype)
- assert_nothing_raised { mount.retrieve }
+ assert_events([:mount_created], fs)
- assert_equal(:mounted, mount.is(:ensure))
+ text = Puppet::Type.type(:mount).fileobj.read
+
+ assert(text =~ /#{fs[:path]}/, "Text did not include new fs")
+
+ fs[:ensure] = :absent
+
+ assert_events([:mount_removed], fs)
+ text = Puppet::Type.type(:mount).fileobj.read
+
+ assert(text !~ /#{fs[:path]}/, "Text still includes new fs")
+
+ fs[:ensure] = :present
+
+ assert_events([:mount_created], fs)
+
+ text = Puppet::Type.type(:mount).fileobj.read
+
+ assert(text =~ /#{fs[:path]}/, "Text did not include new fs")
+
+ fs[:options] = "rw,noauto"
+
+ assert_events([:mount_changed], fs)
end
- # Make sure fs mounting behaves appropriately. This is more a test of
- # whether things get mounted and unmounted based on the value of 'ensure'.
+ if Process.uid == 0
def test_mountfs
- obj = mkmount
+ fs = nil
+ case Facter["hostname"].value
+ when "culain": fs = "/ubuntu"
+ when "atalanta": fs = "/mnt"
+ when "figurehead": fs = "/cg4/net/depts"
+ else
+ $stderr.puts "No mount for mount testing; skipping"
+ return
+ end
+
+ assert_nothing_raised {
+ Puppet.type(:mount).retrieve
+ }
+
+ oldtext = Puppet::Type.type(:mount).fileobj.read
+
+ ftype = Puppet::Type.type(:mount).filetype
+
+ # Make sure the original gets reinstalled.
+ if ftype == Puppet::FileType.filetype(:netinfo)
+ cleanup do
+ IO.popen("niload -r /mounts .", "w") do |file|
+ file.puts oldtext
+ end
+ end
+ else
+ cleanup do
+ Puppet::Type.type(:mount).fileobj.write(oldtext)
+ end
+ end
+
+ obj = Puppet.type(:mount)[fs]
- assert_apply(obj)
+ assert(obj, "Could not retrieve %s object" % fs)
+
+ current = nil
+
+ assert_nothing_raised {
+ current = obj.mounted?
+ }
+
+ if current
+ # Make sure the original gets reinstalled.
+ cleanup do
+ unless obj.mounted?
+ obj.mount
+ end
+ end
+ end
+
+ unless current
+ assert_nothing_raised {
+ obj.mount
+ }
+ end
+
+ # Now copy all of the states' "is" values to the "should" values
+ obj.each do |state|
+ state.should = state.is
+ end
# Verify we can remove the mount
assert_nothing_raised {
obj[:ensure] = :absent
}
- assert_events([:mount_deleted], obj)
+ assert_events([:mount_removed], obj)
assert_events([], obj)
# And verify it's gone
- assert(!obj.provider.mounted?, "Object is mounted after being removed")
+ assert(!obj.mounted?, "Object is mounted after being removed")
+
+ text = Puppet.type(:mount).fileobj.read
+
+ assert(text !~ /#{fs}/,
+ "Fstab still contains %s" % fs)
assert_nothing_raised {
obj[:ensure] = :present
@@ -141,7 +249,10 @@ class TestMounts < Test::Unit::TestCase
assert_events([:mount_created], obj)
assert_events([], obj)
- assert(! obj.provider.mounted?, "Object is mounted incorrectly")
+ text = Puppet::Type.type(:mount).fileobj.read
+ assert(text =~ /#{fs}/, "Fstab does not contain %s" % fs)
+
+ assert(! obj.mounted?, "Object is mounted incorrectly")
assert_nothing_raised {
obj[:ensure] = :mounted
@@ -150,8 +261,33 @@ class TestMounts < Test::Unit::TestCase
assert_events([:mount_mounted], obj)
assert_events([], obj)
+ text = Puppet::Type.type(:mount).fileobj.read
+ assert(text =~ /#{fs}/,
+ "Fstab does not contain %s" % fs)
+
obj.retrieve
- assert(obj.provider.mounted?, "Object is not mounted")
+ assert(obj.mounted?, "Object is not mounted")
+
+ unless current
+ assert_nothing_raised {
+ obj.unmount
+ }
+ end
+ end
+ end
+
+ def use_fake_fstab
+ os = Facter['operatingsystem']
+ if os == "Solaris"
+ name = "solaris.fstab"
+ elsif os == "FreeBSD"
+ name = "freebsd.fstab"
+ else
+ # Catchall for other fstabs
+ name = "linux.fstab"
+ end
+ fstab = fakefile(File::join("data/types/mount", name))
+ Puppet::Type.type(:mount).path = fstab
end
end
diff --git a/test/types/package.rb b/test/types/package.rb
index 9ffd846ef..779c693fe 100644
--- a/test/types/package.rb
+++ b/test/types/package.rb
@@ -167,7 +167,7 @@ class TestPackages < Test::Unit::TestCase
obj[:source] = file
assert_raise(Puppet::PackageError,
"Successfully installed nonexistent package") {
- state.sync(state.should)
+ state.sync
}
end
diff --git a/test/types/port.rb b/test/types/port.rb
index f02825431..debd7ed89 100755
--- a/test/types/port.rb
+++ b/test/types/port.rb
@@ -8,30 +8,29 @@ end
require 'puppettest'
require 'puppet'
+require 'puppet/type/parsedtype/port'
require 'test/unit'
require 'facter'
class TestPort < Test::Unit::TestCase
include TestPuppet
-
def setup
super
@porttype = Puppet.type(:port)
+ @oldfiletype = @porttype.filetype
+ end
- @provider = @porttype.defaultprovider
-
- # Make sure they aren't using something funky like netinfo
- unless @provider.name == :parsed
- @porttype.defaultprovider = @porttype.provider(:parsed)
- end
-
- cleanup do @porttype.defaultprovider = nil end
+ def teardown
+ @porttype.filetype = @oldfiletype
+ Puppet.type(:file).clear
+ super
+ end
- oldpath = @provider.path
- cleanup do
- @provider.path = oldpath
- end
- @provider.path = tempfile()
+ # Here we just create a fake host type that answers to all of the methods
+ # but does not modify our actual system.
+ def mkfaketype
+ pfile = tempfile()
+ @porttype.path = pfile
end
def mkport
@@ -56,29 +55,51 @@ class TestPort < Test::Unit::TestCase
end
def test_simpleport
+ mkfaketype
host = nil
assert_nothing_raised {
- Puppet.type(:port).defaultprovider.retrieve
-
- count = 0
- @porttype.each do |h|
- count += 1
- end
-
- assert_equal(0, count, "Found hosts in empty file somehow")
+ assert_nil(Puppet.type(:port).retrieve)
}
port = mkport
- assert_apply(port)
assert_nothing_raised {
- port.retrieve
+ Puppet.type(:port).store
+ }
+
+ assert_nothing_raised {
+ assert(
+ Puppet.type(:port).to_file.include?(
+ Puppet.type(:port).fileobj.read
+ ),
+ "File does not include all of our objects"
+ )
}
+ end
- assert(port.exists?, "Port did not get created")
+ def test_portsparse
+ fakedata("data/types/ports").each { |file|
+ @porttype.path = file
+ Puppet.info "Parsing %s" % file
+ assert_nothing_raised {
+ @porttype.retrieve
+ }
+
+ # Now just make we've got some ports we know will be there
+ dns = @porttype["domain"]
+ assert(dns, "Could not retrieve DNS port")
+
+ assert_equal("53", dns.is(:number), "DNS number was wrong")
+ %w{udp tcp}.each { |v|
+ assert(dns.is(:protocols).include?(v), "DNS did not include proto %s" % v)
+ }
+
+ @porttype.clear
+ }
end
def test_moddingport
+ mkfaketype
port = nil
port = mkport
@@ -102,24 +123,59 @@ class TestPort < Test::Unit::TestCase
end
def test_removal
+ mkfaketype
port = mkport()
assert_nothing_raised {
port[:ensure] = :present
}
assert_events([:port_created], port)
- assert_events([], port)
- assert(port.exists?, "port was not created")
+ port.retrieve
+ assert(port.insync?)
assert_nothing_raised {
port[:ensure] = :absent
}
- assert_events([:port_deleted], port)
- assert(! port.exists?, "port was not removed")
+ assert_events([:port_removed], port)
+ port.retrieve
assert_events([], port)
end
+ def test_modifyingfile
+ mkfaketype()
+
+ ports = []
+ names = []
+ 3.times {
+ k = mkport()
+ ports << k
+ names << k.name
+ }
+ assert_apply(*ports)
+ ports.clear
+ Puppet.type(:port).clear
+ newport = mkport()
+ #newport[:ensure] = :present
+ names << newport.name
+ assert_apply(newport)
+ Puppet.type(:port).clear
+ # Verify we can retrieve that info
+ assert_nothing_raised("Could not retrieve after second write") {
+ newport.retrieve
+ }
+
+ # And verify that we have data for everything
+ names.each { |name|
+ port = Puppet.type(:port)[name]
+ assert(port)
+ port.retrieve
+ assert(port[:number], "port %s has no number" % name)
+ }
+ end
+
def test_addingstates
+ mkfaketype
+
port = mkport()
assert_events([:port_created], port)
@@ -133,7 +189,7 @@ class TestPort < Test::Unit::TestCase
assert_equal(:present, port.is(:ensure))
- assert_equal(:absent, port.retrieve[:alias])
+ assert(port.state(:alias).is == :absent)
port[:alias] = "yaytest"
assert_events([:port_changed], port)
diff --git a/test/types/sshkey.rb b/test/types/sshkey.rb
index cf8313654..ff9adc336 100755
--- a/test/types/sshkey.rb
+++ b/test/types/sshkey.rb
@@ -17,22 +17,21 @@ class TestSSHKey < Test::Unit::TestCase
def setup
super
# god i'm lazy
- @sshkeytype = Puppet.type(:sshkey)
-
- @provider = @sshkeytype.defaultprovider
-
- # Make sure they aren't using something funky like netinfo
- unless @provider.name == :parsed
- @sshkeytype.defaultprovider = @sshkeytype.provider(:parsed)
- end
+ @sshtype = Puppet.type(:sshkey)
+ @oldfiletype = @sshtype.filetype
+ end
- cleanup do @sshkeytype.defaultprovider = nil end
+ def teardown
+ Puppet::FileType.filetype(:ram).clear
+ @sshtype.filetype = @oldfiletype
+ Puppet.type(:file).clear
+ super
+ end
- oldpath = @provider.path
- cleanup do
- @provider.path = oldpath
- end
- @provider.path = tempfile()
+ # Here we just create a fake key type that answers to all of the methods
+ # but does not modify our actual system.
+ def mkfaketype
+ @sshtype.filetype = Puppet::FileType.filetype(:ram)
end
def mkkey
@@ -45,7 +44,7 @@ class TestSSHKey < Test::Unit::TestCase
end
assert_nothing_raised {
- key = @sshkeytype.create(
+ key = @sshtype.create(
:name => "host%s.madstop.com" % @kcount,
:key => "%sAAAAB3NzaC1kc3MAAACBAMnhSiku76y3EGkNCDsUlvpO8tRgS9wL4Eh54WZfQ2lkxqfd2uT/RTT9igJYDtm/+UHuBRdNGpJYW1Nw2i2JUQgQEEuitx4QKALJrBotejGOAWxxVk6xsh9xA0OW8Q3ZfuX2DDitfeC8ZTCl4xodUMD8feLtP+zEf8hxaNamLlt/AAAAFQDYJyf3vMCWRLjTWnlxLtOyj/bFpwAAAIEAmRxxXb4jjbbui9GYlZAHK00689DZuX0EabHNTl2yGO5KKxGC6Esm7AtjBd+onfu4Rduxut3jdI8GyQCIW8WypwpJofCIyDbTUY4ql0AQUr3JpyVytpnMijlEyr41FfIb4tnDqnRWEsh2H7N7peW+8DWZHDFnYopYZJ9Yu4/jHRYAAACAERG50e6aRRb43biDr7Ab9NUCgM9bC0SQscI/xdlFjac0B/kSWJYTGVARWBDWug705hTnlitY9cLC5Ey/t/OYOjylTavTEfd/bh/8FkAYO+pWdW3hx6p97TBffK0b6nrc6OORT2uKySbbKOn0681nNQh4a6ueR3JRppNkRPnTk5c=" % @kcount,
:type => "ssh-dss",
@@ -57,25 +56,41 @@ class TestSSHKey < Test::Unit::TestCase
end
def test_simplekey
+ mkfaketype
assert_nothing_raised {
- Puppet.type(:sshkey).defaultprovider.retrieve
-
- count = 0
- @sshkeytype.each do |h|
- count += 1
- end
-
- assert_equal(0, count, "Found sshkeys in empty file somehow")
+ assert_nil(Puppet.type(:sshkey).retrieve)
}
key = mkkey
assert_apply(key)
- assert(key.exists?, "Key did not get created")
+ assert_nothing_raised {
+ Puppet.type(:sshkey).store
+ }
+
+ assert_nothing_raised {
+ assert(
+ Puppet.type(:sshkey).to_file.include?(
+ Puppet.type(:sshkey).fileobj.read
+ ),
+ "File does not include all of our objects"
+ )
+ }
+ end
+
+ def test_keysparse
+ fakedata("data/types/sshkey").each { |file|
+ @sshtype.path = file
+ assert_nothing_raised {
+ @sshtype.retrieve
+ }
+ @sshtype.clear
+ }
end
def test_moddingkey
+ mkfaketype
key = mkkey()
assert_events([:sshkey_created], key)
@@ -84,11 +99,12 @@ class TestSSHKey < Test::Unit::TestCase
key[:alias] = %w{madstop kirby yayness}
+ Puppet.err :mark
assert_events([:sshkey_changed], key)
end
def test_aliasisstate
- assert_equal(:state, @sshkeytype.attrtype(:alias))
+ assert_equal(:state, @sshtype.attrtype(:alias))
end
def test_multivalues
@@ -110,23 +126,28 @@ class TestSSHKey < Test::Unit::TestCase
end
def test_removal
+ mkfaketype
sshkey = mkkey()
assert_nothing_raised {
sshkey[:ensure] = :present
}
assert_events([:sshkey_created], sshkey)
- assert(sshkey.exists?, "key was not created")
+ sshkey.retrieve
+ assert(sshkey.insync?)
assert_nothing_raised {
sshkey[:ensure] = :absent
}
- assert_events([:sshkey_deleted], sshkey)
- assert(! sshkey.exists?, "Key was not deleted")
+ assert_events([:sshkey_removed], sshkey)
+ sshkey.retrieve
assert_events([], sshkey)
end
def test_modifyingfile
+ keyfile = tempfile()
+ Puppet.type(:sshkey).path = keyfile
+
keys = []
names = []
3.times {
@@ -143,7 +164,7 @@ class TestSSHKey < Test::Unit::TestCase
#newkey[:ensure] = :present
names << newkey.name
assert_apply(newkey)
-
+ Puppet.type(:sshkey).clear
# Verify we can retrieve that info
assert_nothing_raised("Could not retrieve after second write") {
newkey.retrieve
@@ -151,9 +172,9 @@ class TestSSHKey < Test::Unit::TestCase
# And verify that we have data for everything
names.each { |name|
- key = Puppet.type(:sshkey)[name] || Puppet.type(:sshkey).create(:name => name)
+ key = Puppet.type(:sshkey)[name]
assert(key)
- assert(key.exists?, "key %s is missing" % name)
+ assert(key[:type])
}
end
end
diff --git a/test/types/user.rb b/test/types/user.rb
index 7522a041b..008f39272 100755
--- a/test/types/user.rb
+++ b/test/types/user.rb
@@ -19,7 +19,7 @@ class TestUser < Test::Unit::TestCase
@ensure = :present
@model.eachstate do |state|
next if state.name == :ensure
- state.commit
+ state.sync
end
end