summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/type.rb48
-rwxr-xr-xlib/puppet/type/cron.rb9
-rwxr-xr-xlib/puppet/type/exec.rb2
-rwxr-xr-xlib/puppet/type/group.rb4
-rw-r--r--lib/puppet/type/nameservice/netinfo.rb2
-rw-r--r--lib/puppet/type/nameservice/objectadd.rb4
-rw-r--r--lib/puppet/type/nameservice/posix.rb8
-rw-r--r--lib/puppet/type/package.rb10
-rw-r--r--lib/puppet/type/pfile.rb971
-rwxr-xr-xlib/puppet/type/pfile/pfilechecksum.rb217
-rwxr-xr-xlib/puppet/type/pfile/pfilecreate.rb87
-rwxr-xr-xlib/puppet/type/pfile/pfilegroup.rb115
-rwxr-xr-xlib/puppet/type/pfile/pfilemode.rb108
-rwxr-xr-xlib/puppet/type/pfile/pfilesource.rb257
-rwxr-xr-xlib/puppet/type/pfile/pfiletype.rb31
-rwxr-xr-xlib/puppet/type/pfile/pfileuid.rb103
-rw-r--r--lib/puppet/type/service.rb24
-rw-r--r--lib/puppet/type/state.rb114
-rwxr-xr-xlib/puppet/type/user.rb11
-rwxr-xr-xtest/certmgr/tc_certmgr.rb2
-rw-r--r--test/puppettest.rb14
-rw-r--r--test/server/tc_bucket.rb1
-rw-r--r--test/server/tc_master.rb1
-rw-r--r--test/types/tc_basic.rb15
-rw-r--r--test/types/tc_file.rb7
-rwxr-xr-xtest/types/tc_filebucket.rb1
-rwxr-xr-xtest/types/tc_filesources.rb34
27 files changed, 1112 insertions, 1088 deletions
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index e0c31777b..a460e6024 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -13,8 +13,18 @@ require 'puppet/type/state'
module Puppet
class Type < Puppet::Element
- attr_accessor :children, :parameters, :parent, :implicit
+ attr_accessor :children, :parameters, :parent
attr_accessor :file, :line
+
+ attr_writer :implicit
+ def implicit?
+ if defined? @implicit and @implicit
+ return true
+ else
+ return false
+ end
+ end
+
include Enumerable
# this is currently unused, but I expect to use it for metrics eventually
@@ -513,9 +523,6 @@ class Type < Puppet::Element
if stateklass = self.class.validstate?(name)
if @states.include?(name)
hash.each { |var,value|
- if value.is_a?(Puppet::State)
- raise "huh?"
- end
@states[name].send(var.to_s + "=", value)
}
else
@@ -669,6 +676,12 @@ class Type < Puppet::Element
end
return nil
end
+
+ if implicit
+ obj.implicit = true
+ end
+
+ return obj
end
def self.implicitcreate(hash)
@@ -787,11 +800,28 @@ class Type < Puppet::Element
end
next if param == :name or param == self.class.namevar
- # FIXME we should really allow equal values, but for now, don't allow
- # any values
- if oldval = self.should(param)
- raise Puppet::Error, "Cannot override %s on %s(%s)" %
- [param, self.class.name, self.name]
+ unless value.is_a?(Array)
+ value = [value]
+ end
+
+ # This needs some way to retrieve the original values specified to
+ # 'should'.
+ if oldvals = self.should(param)
+ if oldvals.is_a?(Array)
+ # take the intersection
+ newvals = oldvals & value
+ if newvals.empty?
+ raise Puppet::Error, "No common values for %s on %s(%s)" %
+ [param, self.class.name, self.name]
+ else
+ Puppet.debug "Reduced old values %s and new values %s to %s" %
+ [oldvals.inspect, value.inspect, newvals.inspect]
+ self.should = newvals
+ end
+ else
+ raise Puppet::Error, "Cannot override %s on %s(%s)" %
+ [param, self.class.name, self.name]
+ end
else
self[param] = value
end
diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb
index 274c82ef2..1c9f57caa 100755
--- a/lib/puppet/type/cron.rb
+++ b/lib/puppet/type/cron.rb
@@ -122,12 +122,11 @@ module Puppet
if @is == :notfound
#@is = @should
event = :cron_created
- elsif @should == :notfound
- # FIXME I need to actually delete the cronjob...
- @parent.destroy
+ elsif self.should == :notfound
+ @parent.remove(true)
event = :cron_deleted
- elsif @should == @is
- Puppet.err "Uh, they're both %s" % @should
+ elsif self.should == @is
+ Puppet.err "Uh, they're both %s" % self.should
return nil
else
#@is = @should
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index a86e0207c..634613cc1 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -23,7 +23,7 @@ module Puppet
if file = @parent[:creates]
if FileTest.exists?(file)
@is = true
- @should = true
+ @should = nil
return
end
end
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index 4da1b94b1..be838d70e 100755
--- a/lib/puppet/type/group.rb
+++ b/lib/puppet/type/group.rb
@@ -38,7 +38,7 @@ module Puppet
return highest + 1
end
- def should=(gid)
+ def shouldprocess(gid)
case gid
when String
if gid =~ /^[-0-9]+$/
@@ -59,7 +59,7 @@ module Puppet
Puppet.info "Setting gid to %s" % gid
- @should = gid
+ return gid
end
end
end
diff --git a/lib/puppet/type/nameservice/netinfo.rb b/lib/puppet/type/nameservice/netinfo.rb
index 7fde579e7..16148ffbf 100644
--- a/lib/puppet/type/nameservice/netinfo.rb
+++ b/lib/puppet/type/nameservice/netinfo.rb
@@ -131,7 +131,7 @@ module Puppet
[@parent.class.netinfodir, @parent.name]
if key = self.class.netinfokey
- cmd << key << "'%s'" % @should
+ cmd << key << "'%s'" % self.should
else
raise Puppet::DevError,
"Could not find netinfokey for state %s" %
diff --git a/lib/puppet/type/nameservice/objectadd.rb b/lib/puppet/type/nameservice/objectadd.rb
index 0a6842955..f8fba4419 100644
--- a/lib/puppet/type/nameservice/objectadd.rb
+++ b/lib/puppet/type/nameservice/objectadd.rb
@@ -58,7 +58,7 @@ module Puppet
[
"groupmod",
self.class.objectaddflag,
- "'%s'" % @should,
+ "'%s'" % self.should,
@parent.name
].join(" ")
end
@@ -100,7 +100,7 @@ module Puppet
cmd = [
"usermod",
self.class.objectaddflag,
- "'%s'" % @should,
+ "'%s'" % self.should,
@parent.name
].join(" ")
end
diff --git a/lib/puppet/type/nameservice/posix.rb b/lib/puppet/type/nameservice/posix.rb
index af62b72ce..8b764ba71 100644
--- a/lib/puppet/type/nameservice/posix.rb
+++ b/lib/puppet/type/nameservice/posix.rb
@@ -98,18 +98,18 @@ module Puppet
def sync
event = nil
# they're in sync some other way
- if @is == @should
+ if self.insync?
return nil
end
if @is == :notfound
self.retrieve
- if @is == @should
+ if self.insync?
return nil
end
end
# if the object needs to be created or deleted,
# depend on another method to do it all at once
- if @is == :notfound or @should == :notfound
+ if @is == :notfound or self.should == :notfound
event = syncname()
return event
@@ -152,7 +152,7 @@ module Puppet
def syncname
cmd = nil
event = nil
- if @should == :notfound
+ if self.should == :notfound
# we need to remove the object...
unless @parent.exists?
# the group already doesn't exist
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index f08410912..6c8057576 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -24,14 +24,14 @@ module Puppet
end
end
- def should=(value)
+ def shouldprocess(value)
# possible values are: true, false, and a version number
case value
#when true, /^[0-9]/:
when true:
- @should = value
+ return value
when false:
- @should = :notinstalled
+ return :notinstalled
else
raise Puppet::Error.new(
"Invalid install value %s" % value
@@ -42,7 +42,7 @@ module Puppet
def sync
method = nil
event = nil
- case @should
+ case @should[0]
when true:
method = :install
event = :package_installed
@@ -50,7 +50,7 @@ module Puppet
method = :remove
event = :package_removed
else
- raise Puppet::Error, "Invalid should value %s" % @should
+ raise Puppet::Error, "Invalid should value %s" % @should[0]
end
if @parent.respond_to?(method)
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb
index 858b1995d..c09ed5de9 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/pfile.rb
@@ -1,7 +1,3 @@
-#!/usr/local/bin/ruby -w
-
-# $Id$
-
require 'digest/md5'
require 'cgi'
require 'etc'
@@ -10,893 +6,19 @@ require 'fileutils'
require 'puppet/type/state'
require 'puppet/server/fileserver'
-module Puppet
- # we first define all of the state that our file will use
- # because the objects must be defined for us to use them in our
- # definition of the file object
- class State
- class PFileType < Puppet::State
- require 'etc'
- @doc = "A read-only state to check the file type."
- @name = :type
-
- def should=(value)
- raise Puppet::Error, ":type is read-only"
- end
-
- def retrieve
- if stat = @parent.stat(true)
- @is = stat.ftype
- else
- @is = :notfound
- end
-
- # so this state is never marked out of sync
- @should = @is
- end
-
-
- def sync
- raise Puppet::Error, ":type is read-only"
- end
- end
-
- class PFileCreate < Puppet::State
- require 'etc'
- @doc = "Whether to create files that don't currently exist.
- **false**/*true*/*file*/*directory*"
- @name = :create
- @event = :file_created
-
- def should=(value)
- # default to just about anything meaning 'true'
- case value
- when "false", false, nil:
- @should = false
- when "true", true, "file", "plain", /^f/:
- @should = "file"
- when "directory", /^d/:
- @should = "directory"
- when :notfound:
- # this is where a creation is being rolled back
- @should = :notfound
- else
- error = Puppet::Error.new "Cannot create files of type %s" %
- value
- raise error
- end
- end
-
- def retrieve
- if stat = @parent.stat(true)
- @is = stat.ftype
- else
- @is = :notfound
- end
-
- #Puppet.debug "'exists' state is %s" % self.is
- end
-
-
- def sync
- event = nil
- mode = nil
- if mstate = @parent.state(:mode)
- mode = mstate.should
- end
- begin
- case @should
- when "file":
- # just create an empty file
- if mode
- File.open(@parent[:path],"w", mode) {
- }
- @parent.delete(:mode)
- else
- File.open(@parent[:path],"w") {
- }
- end
- event = :file_created
- when "directory":
- if mode
- Dir.mkdir(@parent.name,mode)
- @parent.delete(:mode)
- else
- Dir.mkdir(@parent.name)
- end
- event = :directory_created
- when :notfound:
- # this is where the file should be deleted...
- unless FileTest.size(@parent.name) == 0
- raise Puppet::Error.new(
- "Created file %s has since been modified; cannot roll back."
- )
- end
-
- File.unlink(@parent.name)
- else
- error = Puppet::Error.new(
- "Somehow got told to create a %s file" % @should)
- raise error
- end
- rescue => detail
- raise Puppet::Error.new("Could not create %s: %s" %
- [@should, detail]
- )
- end
- return event
- end
- end
-
- class PFileChecksum < Puppet::State
- attr_accessor :checktype
- @doc = "How to check whether a file has changed. **md5**/*lite-md5*/
- *time*/*mtime*"
- @name = :checksum
- @event = :file_modified
-
- @unmanaged = true
-
- def should=(value)
- @checktype = value
- state = Puppet::Storage.state(self)
- if hash = state[@parent[:path]]
- if hash.include?(@checktype)
- @should = hash[@checktype]
- #Puppet.debug "Found checksum %s for %s" %
- # [@should,@parent[:path]]
- else
- #Puppet.debug "Found checksum for %s but not of type %s" %
- # [@parent[:path],@checktype]
- @should = -2
- end
- else
- # We can't use :notfound here, because then it'll match on
- # non-existent files
- @should = -2
- end
- end
-
- def retrieve
- unless defined? @checktype
- @checktype = "md5"
- end
-
- unless FileTest.exists?(@parent.name)
- Puppet.err "File %s does not exist" % @parent.name
- self.is = :notfound
- return
- end
-
- sum = ""
- case @checktype
- when "md5", "md5lite":
- if FileTest.directory?(@parent[:path])
- #Puppet.info "Cannot MD5 sum directory %s" %
- # @parent[:path]
-
- # because we cannot sum directories, just delete ourselves
- # from the file
- # is/should so we won't sync
- @parent.delete(self.name)
- return
- else
- begin
- File.open(@parent[:path]) { |file|
- text = nil
- if @checktype == "md5"
- text = file.read
- else
- text = file.read(512)
- end
- if text.nil?
- Puppet.info "Not checksumming empty file %s" %
- @parent.name
- sum = 0
- else
- sum = Digest::MD5.hexdigest(text)
- end
- }
- rescue Errno::EACCES => detail
- Puppet.notice "Cannot checksum %s: permission denied" %
- @parent.name
- @parent.delete(self.class.name)
- rescue => detail
- Puppet.notice "Cannot checksum %s: %s" %
- detail
- @parent.delete(self.class.name)
- end
- end
- when "timestamp","mtime":
- sum = File.stat(@parent[:path]).mtime.to_s
- when "time":
- sum = File.stat(@parent[:path]).ctime.to_s
- else
- raise Puppet::Error, "Invalid sum time %s" % @checktype
- end
-
- self.is = sum
-
- # if we don't have a 'should' value, then go ahead and mark it
- if ! defined? @should or @should == -2
- @should = sum
- # FIXME we should support an updatechecksums-like mechanism
- self.updatesum
- end
-
- #Puppet.debug "checksum state is %s" % self.is
- end
-
-
- # at this point, we don't actually modify the system, we modify
- # the stored state to reflect the current state, and then kick
- # off an event to mark any changes
- def sync
- if @is.nil?
- error = Puppet::Error.new "Checksum state for %s is somehow nil" %
- @parent.name
- raise error
- end
-
- if @is == :notfound
- self.retrieve
-
- if @is == @should
- Puppet.debug "Checksum is already in sync"
- return nil
- end
- #Puppet.debug "%s(%s): after refresh, is '%s'" %
- # [self.class.name,@parent.name,@is]
-
- # if we still can't retrieve a checksum, it means that
- # the file still doesn't exist
- if @is == :notfound
- # if they're copying, then we won't worry about the file
- # not existing yet
- unless @parent.state(:source)
- Puppet.warning "File %s does not exist -- cannot checksum" %
- @parent.name
- end
- return nil
- end
- end
-
- if self.updatesum
- # set the @should value to the new @is value
- # most important for testing
- #@should = @is
- return :file_modified
- else
- # set the @should value, because it starts out as nil
- #@should = @is
- return nil
- end
- end
-
- def updatesum
- result = false
- state = Puppet::Storage.state(self)
- unless state.include?(@parent.name)
- Puppet.debug "Initializing state hash for %s" %
- @parent.name
-
- state[@parent.name] = Hash.new
- end
-
- if @is == :notfound
- error = Puppet::Error.new("%s has invalid checksum" %
- @parent.name)
- raise error
- #elsif @should == :notfound
- # error = Puppet::Error.new("%s has invalid 'should' checksum" %
- # @parent.name)
- # raise error
- end
-
- # if we're replacing, vs. updating
- if state[@parent.name].include?(@checktype)
- unless defined? @should
- raise Puppet::Error.new(
- ("@should is not initialized for %s, even though we " +
- "found a checksum") % @parent[:path]
- )
- end
- Puppet.debug "Replacing %s checksum %s with %s" %
- [@parent.name, state[@parent.name][@checktype],@is]
- #Puppet.debug "@is: %s; @should: %s" % [@is,@should]
- result = true
- else
- Puppet.debug "Creating checksum %s for %s of type %s" %
- [self.is,@parent.name,@checktype]
- result = false
- end
- state[@parent.name][@checktype] = @is
- return result
- end
- end
-
- class PFileUID < Puppet::State
- require 'etc'
- @doc = "To whom the file should belong. Argument can be user name or
- user ID."
- @name = :owner
- @event = :inode_changed
-
- def retrieve
- # if we're not root, then we can't chown anyway
-# unless Process.uid == 0
-# @parent.delete(self.name)
-# @should = nil
-# @is = nil
-# unless defined? @@notifieduid
-# Puppet.notice "Cannot manage ownership unless running as root"
-# @@notifieduid = true
-# return
-# end
-# end
-
- unless stat = @parent.stat(true)
- @is = :notfound
- return
- end
-
- self.is = stat.uid
- end
-
- # If we're not root, we can check the values but we cannot change them
- def should=(value)
- #unless Process.uid == 0
- # @should = nil
- # @is = nil
- # unless defined? @@notifieduid
- # Puppet.notice "Cannot manage ownership unless running as root"
- # #@parent.delete(self.name)
- # @@notifieduid = true
- # end
- # return
- #if @parent.state(:owner)
- # @parent.delete(:owner)
- #end
- #raise Puppet::Error.new(
- # "Cannot manage ownership unless running as root"
- #)
- #end
- if value.is_a?(Integer)
- # verify the user is a valid user
- begin
- user = Etc.getpwuid(value)
- if user.uid == ""
- error = Puppet::Error.new(
- "Could not retrieve uid for '%s'" %
- @parent.name)
- raise error
- end
- rescue ArgumentError => detail
- raise Puppet::Error.new("User ID %s does not exist" %
- value
- )
- rescue => detail
- raise Puppet::Error.new(
- "Could not find user '%s': %s" % [value, detail])
- raise error
- end
- else
- begin
- user = Etc.getpwnam(value)
- if user.uid == ""
- error = Puppet::Error.new(
- "Could not retrieve uid for '%s'" %
- @parent.name)
- raise error
- end
- value = user.uid
- rescue ArgumentError => detail
- raise Puppet::Error.new("User %s does not exist" %
- value
- )
- rescue => detail
- error = Puppet::Error.new(
- "Could not find user '%s': %s" % [value, detail])
- raise error
- end
- end
-
- @should = value
- end
-
- def sync
- unless Process.uid == 0
- unless defined? @@notifieduid
- Puppet.notice "Cannot manage ownership unless running as root"
- #@parent.delete(self.name)
- @@notifieduid = true
- end
- # there's a possibility that we never got retrieve() called
- # e.g., if the file didn't exist
- # thus, just delete ourselves now and don't do any work
- #@parent.delete(self.name)
- return nil
- end
-
- if @is == :notfound
- @parent.stat(true)
- self.retrieve
- #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
- end
-
- unless @parent.stat
- Puppet.err "File '%s' does not exist; cannot chown" %
- @parent[:path]
- return nil
- end
-
- begin
- File.chown(self.should,nil,@parent[:path])
- rescue => detail
- raise Puppet::Error, "Failed to set owner of '%s' to '%s': %s" %
- [@parent[:path],self.should,detail]
- end
-
- return :inode_changed
- end
- end
-
- # this state should actually somehow turn into many states,
- # one for each bit in the mode
- # I think MetaStates are the answer, but I'm not quite sure
- class PFileMode < Puppet::State
- require 'etc'
- @doc = "Mode the file should be. Currently relatively limited:
- you must specify the exact mode the file should be."
- @name = :mode
- @event = :inode_changed
-
- # our modes are octal, so print them in decimal instead
- def is_to_s
- "%o" % @is
- end
-
- def should_to_s
- "%o" % @should
- end
-
- def should=(should)
- # this is pretty hackish, but i need to make sure the number is in
- # octal, yet the number can only be specified as a string right now
- unless should.is_a?(Integer) # i've already converted it correctly
- unless should =~ /^0/
- should = "0" + should
- end
- should = Integer(should)
- end
- @should = should
- if FileTest.exists?(@parent.name)
- self.dirfix
- end
- end
-
- def dirfix
- # if we're a directory, we need to be executable for all cases
- # that are readable
- if FileTest.directory?(@parent.name)
- if @should & 0400 != 0
- @should |= 0100
- end
- if @should & 040 != 0
- @should |= 010
- end
- if @should & 04 != 0
- @should |= 01
- end
- end
-
- @fixed = true
- end
-
- def retrieve
- if stat = @parent.stat(true)
- self.is = stat.mode & 007777
- unless defined? @fixed
- if defined? @should and @should
- self.dirfix
- end
- end
- else
- self.is = :notfound
- end
-
- #Puppet.debug "chmod state is %o" % self.is
- end
-
- def sync
- if @is == :notfound
- @parent.stat(true)
- self.retrieve
- #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
- if @is == :notfound
- @parent.log "%s does not exist; cannot set mode" %
- @parent.name
- return nil
- end
- end
-
- unless defined? @fixed
- self.dirfix
- end
-
- begin
- File.chmod(@should,@parent[:path])
- rescue => detail
- error = Puppet::Error.new("failed to chmod %s: %s" %
- [@parent.name, detail.message])
- raise error
- end
- return :inode_changed
- end
- end
-
- class PFileGroup < Puppet::State
- require 'etc'
- @doc = "Which group should own the file. Argument can be either group
- name or group ID."
- @name = :group
- @event = :inode_changed
-
- def retrieve
- stat = @parent.stat(true)
-
- self.is = stat.gid
-
- # we probably shouldn't actually modify the 'should' value
- # but i don't see a good way around it right now
- # mmmm, should
- #if defined? @should
- #else
- # @parent.delete(self.name)
- #end
- end
-
- def should=(value)
- method = nil
- gid = nil
- gname = nil
-
- #unless Process.uid == 0
- # unless defined? @@notifiedgroup
- # Puppet.notice(
- # "Cannot manage group unless running as root"
- # )
- # @@notifiedgroup = true
- # end
- # return
- #end
-#
- if value.is_a?(Integer)
- method = :getgrgid
- else
- method = :getgrnam
- end
-
- begin
- group = Etc.send(method,value)
-
- # at one time, os x was putting the gid into the passwd
- # field of the group struct, but that appears to not
- # be the case any more
- #os = Puppet::Fact["Operatingsystem"]
- #case os
- #when "Darwin":
- # #gid = group.passwd
- # gid = group.gid
- #else
- #end
-
- gid = group.gid
- gname = group.name
-
- rescue ArgumentError => detail
- raise Puppet::Error.new(
- "Could not find group %s" % value)
- rescue => detail
- raise Puppet::Error.new(
- "Could not find group %s: %s" % [self.should,detail])
- end
- if gid.nil?
- raise Puppet::Error.new(
- "Could not retrieve gid for %s" % @parent.name)
- end
-
- # now make sure the user is allowed to change to that group
- unless Process.uid == 0
- groups = %x{groups}.chomp.split(/\s/)
- unless groups.include?(gname)
- Puppet.notice "Cannot chgrp: not in group %s" % gname
- raise Puppet::Error.new(
- "Cannot chgrp: not in group %s" % gname)
- end
- end
-
- if gid.nil?
- raise Puppet::Error.new(
- "Nil gid for %s" % @parent.name)
- else
- @should = gid
- end
- end
-
- # 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
- #unless Process.uid == 0
- # unless defined? @@notifiedgroup
- # Puppet.notice(
- # "Cannot manage group ownership unless running as root"
- # )
- # @@notifiedgroup = true
- # end
- # return nil
- #end
-
- Puppet.debug "setting chgrp state to %s" % self.should
- if @is == :notfound
- @parent.stat(true)
- self.retrieve
- #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
- end
-
- unless @parent.stat
- Puppet.err "File '%s' does not exist; cannot chgrp" %
- @parent[:path]
- return nil
- end
-
- begin
- # set owner to nil so it's ignored
- File.chown(nil,self.should,@parent[:path])
- rescue => detail
- error = Puppet::Error.new( "failed to chgrp %s to %s: %s" %
- [@parent[:path], self.should, detail.message])
- raise error
- end
- return :inode_changed
- end
- end
-
- # Copy files from a local or remote source.
- class PFileSource < Puppet::State
- attr_accessor :source, :local
- @doc = "Copy a file over the current file. Uses `checksum` to
- determine when a file should be copied. Valid values are either
- fully qualified paths to files, or URIs. Currently supported URI
- types are *puppet* and *file*."
- @name = :source
-
- # Ask the file server to describe our file.
- def describe
- source = @source
-
- sourceobj, path = @parent.uri2obj(source)
- server = sourceobj.server
-
- begin
- desc = server.describe(path)
- rescue NetworkClientError => detail
- Puppet.err "Could not describe %s: %s" %
- [path, detail]
- return nil
- end
-
- args = {}
- Puppet::Type::PFile::PINPARAMS.zip(
- desc.split("\t")
- ).each { |param, value|
- if value =~ /^[0-9]+$/
- value = value.to_i
- end
- args[param] = value
- }
-
- # we can't manage ownership as root, so don't even try
- unless Process.uid == 0
- args.delete(:owner)
- end
-
- return args
- end
-
- # This basically calls describe() on our file, and then sets all
- # of the local states appropriately. If the remote file is a normal
- # file then we set it to copy; if it's a directory, then we just mark
- # that the local directory should be created.
- def retrieve
- sum = nil
-
- # Describe the remote file.
- @stats = self.describe
- if @stats.nil? or @stats[:type].nil?
- @is = :notdescribed
- return nil
- end
-
- # Take each of the stats and set them as states on the local file
- # if a value has not already been provided.
- @stats.each { |stat, value|
- next if stat == :checksum
- next if stat == :type
-
- # was the stat already specified, or should the value
- # be inherited from the source?
- unless @parent.argument?(stat)
- if state = @parent.state(stat)
- state.should = value
- else
- @parent[stat] = value
- end
- end
- }
-
- # If we're a normal file, then set things up to copy the file down.
- case @stats[:type]
- when "file":
- if sum = @parent.state(:checksum)
- if sum.is
- if sum.is == :notfound
- sum.retrieve
- end
- @is = sum.is
- else
- @is = :notfound
- end
- else
- @is = :notfound
- end
-
- @should = @stats[:checksum]
-
- if state = @parent.state(:create)
- unless state.should == "file"
- Puppet.notice(
- "File %s had both create and source enabled" %
- @parent.name
- )
- @parent.delete(:create)
- end
- end
- # If we're a directory, then do not copy anything, and instead just
- # create the directory using the 'create' state.
- when "directory":
- if state = @parent.state(:create)
- unless state.should == "directory"
- state.should = "directory"
- end
- else
- @parent[:create] = "directory"
- @parent.state(:create).retrieve
- end
- # we'll let the :create state do our work
- @should = true
- @is = true
- # FIXME We should at least support symlinks, I would think...
- else
- Puppet.err "Cannot use files of type %s as sources" %
- @stats[:type]
- @should = true
- @is = true
- end
- end
-
- # The special thing here is that we need to make sure that 'should'
- # is only set for files, not directories.
- def should=(source)
- if ! defined? @stats or @stats.nil?
- @source = source
-
- # stupid hack for now; it'll get overriden
- @should = source
- else
- if @stats[:type] == "directory"
- @should = true
- @is = true
- else
- @source = source
- @should = source
- end
- end
- end
-
- def sync
- if @is == :notdescribed
- self.retrieve # try again
- if @is == :notdescribed
- @parent.log "Could not retreive information on %s" % @parent.name
- return nil
- end
- if @is == @should
- return nil
- end
- end
-
- unless @stats[:type] == "file"
- if @stats[:type] == "directory"
- [@parent.name, @is.inspect, @should.inspect]
- end
- raise Puppet::DevError, "Got told to copy non-file %s" %
- @parent.name
- end
-
- sourceobj, path = @parent.uri2obj(@source)
-
- begin
- contents = sourceobj.server.retrieve(path)
- rescue NetworkClientError => detail
- Puppet.err "Could not retrieve %s: %s" %
- [path, detail]
- return nil
- end
-
- unless sourceobj.server.local
- contents = CGI.unescape(contents)
- end
-
- if contents == ""
- Puppet.notice "Could not retrieve contents for %s" %
- @source
- end
-
- if FileTest.exists?(@parent.name)
- # this makes sure we have a copy for posterity
- @backed = @parent.handlebackup
- end
-
- # create the file in a tmp location
- args = [@parent.name + ".puppettmp",
- File::CREAT | File::WRONLY | File::TRUNC]
-
- # try to create it with the correct modes to start
- # we should also be changing our effective uid/gid, but...
- if @parent.should(:mode) and @parent.should(:mode) != :notfound
- args.push @parent.should(:mode)
- end
-
- # FIXME we should also change our effective user and group id
-
- begin
- File.open(*args) { |f|
- f.print contents
- }
- rescue => detail
- # since they said they want a backup, let's error out
- # if we couldn't make one
- raise Puppet::Error, "Could not create %s to %s: %s" %
- [@source, @parent.name, detail.message]
- end
-
- if FileTest.exists?(@parent.name)
- begin
- File.unlink(@parent.name)
- rescue => detail
- Puppet.err "Could not remove %s for replacing: %s" %
- [@parent.name, detail]
- end
- end
-
- begin
- File.rename(@parent.name + ".puppettmp", @parent.name)
- rescue => detail
- Puppet.err "Could not rename tmp %s for replacing: %s" %
- [@parent.name, detail]
- end
-
- return :file_changed
- end
- end
- end
+# We put all of the states in separate files, because there are so many
+# of them.
+require 'puppet/type/pfile/pfiletype'
+require 'puppet/type/pfile/pfilecreate'
+require 'puppet/type/pfile/pfilechecksum'
+require 'puppet/type/pfile/pfileuid'
+require 'puppet/type/pfile/pfilemode'
+require 'puppet/type/pfile/pfilegroup'
+require 'puppet/type/pfile/pfilesource'
+module Puppet
class Type
class PFile < Type
- # FIXME i don't think these are used
- attr_reader :params, :source, :srcbase
@doc = "Manages local files, including setting ownership and
permissions, and allowing creation of both files and directories."
@@ -1044,7 +166,6 @@ module Puppet
# default to true
self[:backup] = true
- @srcbase = nil
super
end
@@ -1098,8 +219,7 @@ module Puppet
end
def newchild(path, hash = {})
-
- #make local copy of arguments
+ # make local copy of arguments
args = @arghash.dup
if path =~ %r{^#{File::SEPARATOR}}
@@ -1112,25 +232,6 @@ module Puppet
args[:path] = path
-=begin
- # FIXME I think this is obviated now
- unless hash.include?(:source) # it's being manually overridden
- if args.include?(:source)
- Puppet.err "Rewriting source for %s" % path
- name = File.basename(path)
- dirname = args[:source]
- #Puppet.notice "Old: %s" % args[:source]
- #Puppet.notice "New: %s" % File.join(dirname,name)
- if FileTest.exists?(dirname) and ! FileTest.directory?(dirname)
- Puppet.err "Cannot make a child of %s" % dirname
- exit
- end
- args[:source] = File.join(dirname,name)
- end
-
- end
-=end
-
unless hash.include?(:recurse)
if args.include?(:recurse)
if args[:recurse].is_a?(Integer)
@@ -1145,10 +246,6 @@ module Puppet
args[key] = value
}
- #if @states.include?(:checksum)
- # args[:checksum] = @states[:checksum].checktype
- #end
-
child = nil
klass = nil
if @parameters[:linkmaker] and args.include?(:source) and
@@ -1166,28 +263,24 @@ module Puppet
klass = self.class
end
- # We know we're creating an implicit child. If the child we're
- # trying to create already exists, then we know it should still
- # be there, since if it shouldn't be, it would have already been
- # removed. Either it's entirely explicit, in which case it
- # should win, or it's implicit but resulting from a more explicit
- # child.
+ # The child might already exist because 'localrecurse' runs
+ # before 'sourcerecurse'. I could push the override stuff into
+ # a separate method or something, but the work is the same other
+ # than this last bit, so it doesn't really make sense.
if child = klass[path]
- Puppet.warning "Not managing more explicit %s" % child
- return nil
- #unless @children.include?(child)
- # raise Puppet::Error,
- # "Planned child file %s of %s already exists with parent %s" %
- # [path, self.name, child.parent]
- #end
- #args.each { |var,value|
- # next if var == :path
- # next if var == :name
- # # behave idempotently
- # unless child.should(var) == value
- # child[var] = value
- # end
- #}
+ unless @children.include?(child)
+ Puppet.notice "Not managing more explicit file %s" %
+ path
+ return nil
+ end
+ args.each { |var,value|
+ next if var == :path
+ next if var == :name
+ # behave idempotently
+ unless child.should(var) == value
+ child[var] = value
+ end
+ }
else # create it anew
#notice "Creating new file with args %s" % args.inspect
begin
@@ -1218,6 +311,8 @@ module Puppet
return child
end
+ # Recurse into the directory. This basically just calls 'localrecurse'
+ # and maybe 'sourcerecurse'.
def recurse
recurse = @parameters[:recurse]
# we might have a string, rather than a number
@@ -1417,8 +512,8 @@ module Puppet
end
else
raise Puppet::Error,
- "Got other recursive file proto %s" % uri.scheme
- return
+ "Got other recursive file proto %s from %s" %
+ [uri.scheme, source]
end
return [sourceobj, path.sub(/\/\//, '/')]
@@ -1432,3 +527,5 @@ module Puppet
attr_accessor :mount, :root, :server, :local
end
end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfilechecksum.rb b/lib/puppet/type/pfile/pfilechecksum.rb
new file mode 100755
index 000000000..8747cfeb5
--- /dev/null
+++ b/lib/puppet/type/pfile/pfilechecksum.rb
@@ -0,0 +1,217 @@
+# Keep a copy of the file checksums, and notify when they change.
+
+# This state never actually modifies the system, it only notices when the system
+# changes on its own.
+module Puppet
+ class State
+ class PFileChecksum < Puppet::State
+ @doc = "How to check whether a file has changed. **md5**/*lite-md5*/
+ *time*/*mtime*"
+ @name = :checksum
+ @event = :file_modified
+
+ @unmanaged = true
+
+ @validtypes = %w{md5 md5lite timestamp mtime time}
+
+ def self.validtype?(type)
+ @validtypes.include?(type)
+ end
+
+ def getsum(checktype)
+ sum = ""
+ case checktype
+ when "md5", "md5lite":
+ unless FileTest.file?(@parent[:path])
+ #Puppet.info "Cannot MD5 sum directory %s" %
+ # @parent[:path]
+
+ # because we cannot sum directories, just delete ourselves
+ # from the file so we won't sync
+ @parent.delete(self.name)
+ return
+ else
+ begin
+ File.open(@parent[:path]) { |file|
+ text = nil
+ if checktype == "md5"
+ text = file.read
+ else
+ text = file.read(512)
+ end
+ if text.nil?
+ Puppet.info "Not checksumming empty file %s" %
+ @parent.name
+ sum = 0
+ else
+ sum = Digest::MD5.hexdigest(text)
+ end
+ }
+ rescue Errno::EACCES => detail
+ Puppet.notice "Cannot checksum %s: permission denied" %
+ @parent.name
+ @parent.delete(self.class.name)
+ rescue => detail
+ Puppet.notice "Cannot checksum %s: %s" %
+ detail
+ @parent.delete(self.class.name)
+ end
+ end
+ when "timestamp","mtime":
+ sum = File.stat(@parent[:path]).mtime.to_s
+ when "time":
+ sum = File.stat(@parent[:path]).ctime.to_s
+ else
+ raise Puppet::Error, "Invalid sum type %s" % checktype
+ end
+
+ return sum
+ end
+
+ # Convert from the sum type to the stored checksum.
+ def shouldprocess(value)
+ unless self.class.validtype?(value)
+ raise Puppet::Error, "Invalid checksum type '%s'" % value
+ end
+ state = Puppet::Storage.state(self)
+ if hash = state[@parent[:path]]
+ if hash.include?(value)
+ return hash[value]
+ #Puppet.debug "Found checksum %s for %s" %
+ # [self.should,@parent[:path]]
+ else
+ #Puppet.debug "Found checksum for %s but not of type %s" %
+ # [@parent[:path],@checktype]
+ return :nosum
+ end
+ else
+ # We can't use :notfound here, because then it'll match on
+ # non-existent files
+ return :nosum
+ end
+ end
+
+ # Even though they can specify multiple checksums, the insync?
+ # mechanism can really only test against one, so we'll just retrieve
+ # the first specified sum type.
+ def retrieve
+ checktypes = nil
+ if defined? @shouldorig
+ checktypes = @shouldorig
+ else
+ checktypes = ["md5"]
+ end
+
+ unless FileTest.exists?(@parent.name)
+ Puppet.err "File %s does not exist" % @parent.name
+ self.is = :notfound
+ return
+ end
+
+ # Just use the first allowed check type
+ @checktype = checktypes[0]
+
+ @is = getsum(@checktype)
+
+ # If there is no should defined, then store the current value
+ # into the 'should' value, so that we're not marked as being
+ # out of sync. We don't want to generate an event the first
+ # time we get a sum.
+ if ! defined? @should or @should == [:nosum]
+ @should = [@is]
+ # FIXME we should support an updatechecksums-like mechanism
+ self.updatesum
+ end
+
+ #Puppet.debug "checksum state is %s" % self.is
+ end
+
+
+ # At this point, we don't actually modify the system, we modify
+ # the stored state to reflect the current state, and then kick
+ # off an event to mark any changes.
+ def sync
+ if @is.nil?
+ raise Puppet::Error, "Checksum state for %s is somehow nil" %
+ @parent.name
+ end
+
+ if @is == :notfound
+ self.retrieve
+
+ if self.insync?
+ Puppet.debug "Checksum is already in sync"
+ return nil
+ end
+ #Puppet.debug "%s(%s): after refresh, is '%s'" %
+ # [self.class.name,@parent.name,@is]
+
+ # If we still can't retrieve a checksum, it means that
+ # the file still doesn't exist
+ if @is == :notfound
+ # if they're copying, then we won't worry about the file
+ # not existing yet
+ unless @parent.state(:source)
+ Puppet.warning(
+ "File %s does not exist -- cannot checksum" %
+ @parent.name
+ )
+ end
+ return nil
+ end
+ end
+
+ # If the sums are different, then return an event.
+ if self.updatesum
+ return :file_modified
+ else
+ return nil
+ end
+ end
+
+ # Store the new sum to the state db.
+ def updatesum
+ result = false
+ state = Puppet::Storage.state(self)
+ unless state.include?(@parent.name)
+ Puppet.debug "Initializing state hash for %s" %
+ @parent.name
+
+ state[@parent.name] = Hash.new
+ end
+
+ if @is.is_a?(Symbol)
+ error = Puppet::Error.new("%s has invalid checksum" %
+ @parent.name)
+ raise error
+ #elsif @should == :notfound
+ # error = Puppet::Error.new("%s has invalid 'should' checksum" %
+ # @parent.name)
+ # raise error
+ end
+
+ # if we're replacing, vs. updating
+ if state[@parent.name].include?(@checktype)
+ unless defined? @should
+ raise Puppet::Error.new(
+ ("@should is not initialized for %s, even though we " +
+ "found a checksum") % @parent[:path]
+ )
+ end
+ Puppet.debug "Replacing %s checksum %s with %s" %
+ [@parent.name, state[@parent.name][@checktype],@is]
+ #Puppet.debug "@is: %s; @should: %s" % [@is,@should]
+ result = true
+ else
+ Puppet.debug "Creating checksum %s for %s of type %s" %
+ [self.is,@parent.name,@checktype]
+ result = false
+ end
+ state[@parent.name][@checktype] = @is
+ return result
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfilecreate.rb b/lib/puppet/type/pfile/pfilecreate.rb
new file mode 100755
index 000000000..f8b2f3818
--- /dev/null
+++ b/lib/puppet/type/pfile/pfilecreate.rb
@@ -0,0 +1,87 @@
+module Puppet
+ class State
+ class PFileCreate < Puppet::State
+ require 'etc'
+ @doc = "Whether to create files that don't currently exist.
+ **false**/*true*/*file*/*directory*"
+ @name = :create
+ @event = :file_created
+
+ def shouldprocess(value)
+ # default to just about anything meaning 'true'
+ case value
+ when "false", false, nil:
+ return false
+ when "true", true, "file", "plain", /^f/:
+ return "file"
+ when "directory", /^d/:
+ return "directory"
+ when :notfound:
+ # this is where a creation is being rolled back
+ return :notfound
+ else
+ raise Puppet::Error, "Cannot create files of type %s" % value
+ end
+ end
+
+ def retrieve
+ if stat = @parent.stat(true)
+ @is = stat.ftype
+ else
+ @is = :notfound
+ end
+
+ #Puppet.debug "'exists' state is %s" % self.is
+ end
+
+
+ def sync
+ event = nil
+ mode = @parent.should(:mode)
+ begin
+ case self.should
+ when "file":
+ # just create an empty file
+ if mode
+ File.open(@parent[:path],"w", mode) {
+ }
+ @parent.delete(:mode)
+ else
+ File.open(@parent[:path],"w") {
+ }
+ end
+ event = :file_created
+ when "directory":
+ if mode
+ Dir.mkdir(@parent.name,mode)
+ @parent.delete(:mode)
+ else
+ Dir.mkdir(@parent.name)
+ end
+ event = :directory_created
+ when :notfound:
+ # this is where the file should be deleted...
+ unless FileTest.size(@parent.name) == 0
+ raise Puppet::Error.new(
+ "Created file %s has since been modified; cannot roll back."
+ )
+ end
+
+ File.unlink(@parent.name)
+ else
+ error = Puppet::Error.new(
+ "Somehow got told to create a %s file" % self.should)
+ raise error
+ end
+ rescue => detail
+ raise Puppet::Error.new("Could not create %s: %s" %
+ [self.should, detail]
+ )
+ end
+ return event
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfilegroup.rb b/lib/puppet/type/pfile/pfilegroup.rb
new file mode 100755
index 000000000..f38860259
--- /dev/null
+++ b/lib/puppet/type/pfile/pfilegroup.rb
@@ -0,0 +1,115 @@
+# Manage file group ownership.
+module Puppet
+ class State
+ class PFileGroup < Puppet::State
+ require 'etc'
+ @doc = "Which group should own the file. Argument can be either group
+ name or group ID."
+ @name = :group
+ @event = :inode_changed
+
+ def retrieve
+ stat = @parent.stat(true)
+
+ self.is = stat.gid
+ end
+
+ def shouldprocess(value)
+ method = nil
+ gid = nil
+ gname = nil
+
+ if value.is_a?(Integer)
+ method = :getgrgid
+ else
+ method = :getgrnam
+ end
+
+ begin
+ group = Etc.send(method,value)
+
+ # at one time, os x was putting the gid into the passwd
+ # field of the group struct, but that appears to not
+ # be the case any more
+ #os = Puppet::Fact["Operatingsystem"]
+ #case os
+ #when "Darwin":
+ # #gid = group.passwd
+ # gid = group.gid
+ #else
+ #end
+
+ gid = group.gid
+ gname = group.name
+
+ rescue ArgumentError => detail
+ raise Puppet::Error.new(
+ "Could not find group %s" % value)
+ rescue => detail
+ raise Puppet::Error.new(
+ "Could not find group %s: %s" % [self.should,detail])
+ end
+ if gid.nil?
+ raise Puppet::Error.new(
+ "Could not retrieve gid for %s" % @parent.name)
+ end
+
+ # now make sure the user is allowed to change to that group
+ unless Process.uid == 0
+ groups = %x{groups}.chomp.split(/\s/)
+ unless groups.include?(gname)
+ Puppet.notice "Cannot chgrp: not in group %s" % gname
+ raise Puppet::Error.new(
+ "Cannot chgrp: not in group %s" % gname)
+ end
+ end
+
+ if gid.nil?
+ raise Puppet::Error.new(
+ "Nil gid for %s" % @parent.name)
+ else
+ return gid
+ end
+ end
+
+ # 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
+ #unless Process.uid == 0
+ # unless defined? @@notifiedgroup
+ # Puppet.notice(
+ # "Cannot manage group ownership unless running as root"
+ # )
+ # @@notifiedgroup = true
+ # end
+ # return nil
+ #end
+
+ if @is == :notfound
+ @parent.stat(true)
+ self.retrieve
+ #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
+ end
+
+ unless @parent.stat
+ Puppet.err "File '%s' does not exist; cannot chgrp" %
+ @parent[:path]
+ return nil
+ end
+
+ begin
+ # set owner to nil so it's ignored
+ File.chown(nil,self.should,@parent[:path])
+ rescue => detail
+ error = Puppet::Error.new( "failed to chgrp %s to %s: %s" %
+ [@parent[:path], self.should, detail.message])
+ raise error
+ end
+ return :inode_changed
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfilemode.rb b/lib/puppet/type/pfile/pfilemode.rb
new file mode 100755
index 000000000..b432dc639
--- /dev/null
+++ b/lib/puppet/type/pfile/pfilemode.rb
@@ -0,0 +1,108 @@
+# Manage file modes. This state should support different formats
+# for specification (e.g., u+rwx, or -0011), but for now only supports
+# specifying the full mode.
+module Puppet
+ class State
+ class PFileMode < Puppet::State
+ require 'etc'
+ @doc = "Mode the file should be. Currently relatively limited:
+ you must specify the exact mode the file should be."
+ @name = :mode
+ @event = :inode_changed
+
+ # Our modes are octal, so make sure they print correctly.
+ def is_to_s
+ "%o" % @is
+ end
+
+ def should_to_s
+ "%o" % self.should
+ end
+
+ def shouldprocess(should)
+ # this is pretty hackish, but i need to make sure the number is in
+ # octal, yet the number can only be specified as a string right now
+ value = should
+ if value.is_a?(String)
+ unless value =~ /^0/
+ value = "0" + value
+ end
+ value = Integer(value)
+ end
+
+ #Puppet.warning "Should is %o from %s" % [value, should]
+
+ return value
+ end
+
+ # If we're a directory, we need to be executable for all cases
+ # that are readable. This should probably be selectable, but eh.
+ def dirmask(value)
+ if FileTest.directory?(@parent.name)
+ if value & 0400 != 0
+ value |= 0100
+ end
+ if value & 040 != 0
+ value |= 010
+ end
+ if value & 04 != 0
+ value |= 01
+ end
+ end
+
+ return value
+ end
+
+ def retrieve
+ if stat = @parent.stat(true)
+ self.is = stat.mode & 007777
+ unless defined? @fixed
+ if defined? @should and @should
+ @should = @should.collect { |s| self.dirmask(s) }
+ end
+ end
+ else
+ self.is = :notfound
+ end
+
+ #Puppet.debug "chmod state is %o" % self.is
+ end
+
+ def sync
+ if @is == :notfound
+ @parent.stat(true)
+ self.retrieve
+ #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
+ if @is == :notfound
+ @parent.log "%s does not exist; cannot set mode" %
+ @parent.name
+ return nil
+ end
+
+ if self.insync?
+ # we're already in sync
+ return nil
+ end
+ end
+
+ mode = self.should
+
+ if mode == :notfound
+ # This is really only valid for create states...
+ return nil
+ end
+
+ begin
+ File.chmod(mode,@parent[:path])
+ rescue => detail
+ error = Puppet::Error.new("failed to chmod %s: %s" %
+ [@parent.name, detail.message])
+ raise error
+ end
+ return :inode_changed
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfilesource.rb b/lib/puppet/type/pfile/pfilesource.rb
new file mode 100755
index 000000000..ec4f7107b
--- /dev/null
+++ b/lib/puppet/type/pfile/pfilesource.rb
@@ -0,0 +1,257 @@
+module Puppet
+ class State
+ # Copy files from a local or remote source.
+ class PFileSource < Puppet::State
+ attr_accessor :source, :local
+ @doc = "Copy a file over the current file. Uses `checksum` to
+ determine when a file should be copied. Valid values are either
+ fully qualified paths to files, or URIs. Currently supported URI
+ types are *puppet* and *file*."
+ @name = :source
+
+ # Ask the file server to describe our file.
+ def describe(source)
+ sourceobj, path = @parent.uri2obj(source)
+ server = sourceobj.server
+
+ begin
+ desc = server.describe(path)
+ rescue NetworkClientError => detail
+ Puppet.err "Could not describe %s: %s" %
+ [path, detail]
+ return nil
+ end
+
+ args = {}
+ Puppet::Type::PFile::PINPARAMS.zip(
+ desc.split("\t")
+ ).each { |param, value|
+ if value =~ /^[0-9]+$/
+ value = value.to_i
+ end
+ args[param] = value
+ }
+
+ # we can't manage ownership as root, so don't even try
+ unless Process.uid == 0
+ args.delete(:owner)
+ end
+
+ return args
+ end
+
+ # This basically calls describe() on our file, and then sets all
+ # of the local states appropriately. If the remote file is a normal
+ # file then we set it to copy; if it's a directory, then we just mark
+ # that the local directory should be created.
+ def retrieve
+ sum = nil
+
+ unless defined? @shouldorig
+ raise Puppet::DevError, "No sources defined for %s" %
+ @parent.name
+ end
+
+ @source = nil
+
+ # Find the first source that exists. @shouldorig contains
+ # the sources as specified by the user.
+ @shouldorig.each { |source|
+ if @stats = self.describe(source)
+ @source = source
+ break
+ end
+ }
+
+ if @stats.nil? or @stats[:type].nil?
+ @is = :notdescribed
+ @source = nil
+ return nil
+ end
+
+ # Take each of the stats and set them as states on the local file
+ # if a value has not already been provided.
+ @stats.each { |stat, value|
+ next if stat == :checksum
+ next if stat == :type
+
+ # was the stat already specified, or should the value
+ # be inherited from the source?
+ unless @parent.argument?(stat)
+ if state = @parent.state(stat)
+ state.should = value
+ else
+ @parent[stat] = value
+ end
+ end
+ }
+
+ # If we're a normal file, then set things up to copy the file down.
+ case @stats[:type]
+ when "file":
+ if sum = @parent.state(:checksum)
+ if sum.is
+ if sum.is == :notfound
+ sum.retrieve
+ end
+ @is = sum.is
+ else
+ @is = :notfound
+ end
+ else
+ @is = :notfound
+ end
+
+ @should = [@stats[:checksum]]
+
+ if state = @parent.state(:create)
+ unless state.should == "file"
+ Puppet.notice(
+ "File %s had both create and source enabled" %
+ @parent.name
+ )
+ @parent.delete(:create)
+ end
+ end
+ # If we're a directory, then do not copy anything, and instead just
+ # create the directory using the 'create' state.
+ when "directory":
+ if state = @parent.state(:create)
+ unless state.should == "directory"
+ state.should = "directory"
+ end
+ else
+ @parent[:create] = "directory"
+ @parent.state(:create).retrieve
+ end
+ # we'll let the :create state do our work
+ @should = nil
+ @is = true
+ # FIXME We should at least support symlinks, I would think...
+ else
+ Puppet.err "Cannot use files of type %s as sources" %
+ @stats[:type]
+ @should = nil
+ @is = true
+ end
+ end
+
+ # The special thing here is that we need to make sure that 'should'
+ # is only set for files, not directories. The processing we're doing
+ # here doesn't really matter, because the @should values will be
+ # overridden when we 'retrieve'.
+ def shouldprocess(source)
+ unless @parent.uri2obj(source)
+ raise Puppet::Error, "Invalid source %s" % source
+ end
+
+ if ! defined? @stats or @stats.nil?
+ # stupid hack for now; it'll get overriden
+ return source
+ else
+ if @stats[:type] == "directory"
+ @is = true
+ return nil
+ else
+ return source
+ end
+ end
+ end
+
+ def sync
+ if @is == :notdescribed
+ self.retrieve # try again
+ if @is == :notdescribed
+ @parent.log "Could not retreive information on %s" %
+ @parent.name
+ return nil
+ end
+ if @is == @should
+ return nil
+ end
+ end
+
+ unless @stats[:type] == "file"
+ if @stats[:type] == "directory"
+ [@parent.name, @is.inspect, @should.inspect]
+ end
+ raise Puppet::DevError, "Got told to copy non-file %s" %
+ @parent.name
+ end
+
+ unless defined? @source
+ raise Puppet::DevError, "Somehow source is still undefined"
+ end
+
+ sourceobj, path = @parent.uri2obj(@source)
+
+ begin
+ contents = sourceobj.server.retrieve(path)
+ rescue NetworkClientError => detail
+ Puppet.err "Could not retrieve %s: %s" %
+ [path, detail]
+ return nil
+ end
+
+ # FIXME It's stupid that this isn't taken care of in the
+ # protocol.
+ unless sourceobj.server.local
+ contents = CGI.unescape(contents)
+ end
+
+ if contents == ""
+ Puppet.notice "Could not retrieve contents for %s" %
+ @source
+ end
+
+ if FileTest.exists?(@parent.name)
+ # this makes sure we have a copy for posterity
+ @backed = @parent.handlebackup
+ end
+
+ # create the file in a tmp location
+ args = [@parent.name + ".puppettmp",
+ File::CREAT | File::WRONLY | File::TRUNC]
+
+ # try to create it with the correct modes to start
+ # we should also be changing our effective uid/gid, but...
+ if @parent.should(:mode) and @parent.should(:mode) != :notfound
+ args.push @parent.should(:mode)
+ end
+
+ # FIXME we should also change our effective user and group id
+
+ begin
+ File.open(*args) { |f|
+ f.print contents
+ }
+ rescue => detail
+ # since they said they want a backup, let's error out
+ # if we couldn't make one
+ raise Puppet::Error, "Could not create %s to %s: %s" %
+ [@source, @parent.name, detail.message]
+ end
+
+ if FileTest.exists?(@parent.name)
+ begin
+ File.unlink(@parent.name)
+ rescue => detail
+ Puppet.err "Could not remove %s for replacing: %s" %
+ [@parent.name, detail]
+ end
+ end
+
+ begin
+ File.rename(@parent.name + ".puppettmp", @parent.name)
+ rescue => detail
+ Puppet.err "Could not rename tmp %s for replacing: %s" %
+ [@parent.name, detail]
+ end
+
+ return :file_changed
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfiletype.rb b/lib/puppet/type/pfile/pfiletype.rb
new file mode 100755
index 000000000..1d03634e7
--- /dev/null
+++ b/lib/puppet/type/pfile/pfiletype.rb
@@ -0,0 +1,31 @@
+module Puppet
+ class State
+ class PFileType < Puppet::State
+ require 'etc'
+ @doc = "A read-only state to check the file type."
+ @name = :type
+
+ def shouldprocess(value)
+ raise Puppet::Error, ":type is read-only"
+ end
+
+ def retrieve
+ if stat = @parent.stat(true)
+ @is = stat.ftype
+ else
+ @is = :notfound
+ end
+
+ # so this state is never marked out of sync
+ @should = [@is]
+ end
+
+
+ def sync
+ raise Puppet::Error, ":type is read-only"
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/pfile/pfileuid.rb b/lib/puppet/type/pfile/pfileuid.rb
new file mode 100755
index 000000000..176988eb1
--- /dev/null
+++ b/lib/puppet/type/pfile/pfileuid.rb
@@ -0,0 +1,103 @@
+module Puppet
+ class State
+ class PFileUID < Puppet::State
+ require 'etc'
+ @doc = "To whom the file should belong. Argument can be user name or
+ user ID."
+ @name = :owner
+ @event = :inode_changed
+
+ def retrieve
+ unless stat = @parent.stat(true)
+ @is = :notfound
+ return
+ end
+
+ self.is = stat.uid
+ end
+
+ # If we're not root, we can check the values but we cannot change them
+ def shouldprocess(value)
+ if value.is_a?(Integer)
+ # verify the user is a valid user
+ begin
+ user = Etc.getpwuid(value)
+ if user.uid == ""
+ error = Puppet::Error.new(
+ "Could not retrieve uid for '%s'" %
+ @parent.name)
+ raise error
+ end
+ rescue ArgumentError => detail
+ raise Puppet::Error.new("User ID %s does not exist" %
+ value
+ )
+ rescue => detail
+ raise Puppet::Error.new(
+ "Could not find user '%s': %s" % [value, detail])
+ raise error
+ end
+ else
+ begin
+ user = Etc.getpwnam(value)
+ if user.uid == ""
+ error = Puppet::Error.new(
+ "Could not retrieve uid for '%s'" %
+ @parent.name)
+ raise error
+ end
+ value = user.uid
+ rescue ArgumentError => detail
+ raise Puppet::Error.new("User %s does not exist" %
+ value
+ )
+ rescue => detail
+ error = Puppet::Error.new(
+ "Could not find user '%s': %s" % [value, detail])
+ raise error
+ end
+ end
+
+ return value
+ end
+
+ def sync
+ unless Process.uid == 0
+ unless defined? @@notifieduid
+ Puppet.notice "Cannot manage ownership unless running as root"
+ #@parent.delete(self.name)
+ @@notifieduid = true
+ end
+ # there's a possibility that we never got retrieve() called
+ # e.g., if the file didn't exist
+ # thus, just delete ourselves now and don't do any work
+ #@parent.delete(self.name)
+ return nil
+ end
+
+ if @is == :notfound
+ @parent.stat(true)
+ self.retrieve
+ #Puppet.debug "%s: after refresh, is '%s'" % [self.class.name,@is]
+ end
+
+ unless @parent.stat
+ Puppet.err "File '%s' does not exist; cannot chown" %
+ @parent[:path]
+ return nil
+ end
+
+ begin
+ File.chown(self.should,nil,@parent[:path])
+ rescue => detail
+ raise Puppet::Error, "Failed to set owner of '%s' to '%s': %s" %
+ [@parent[:path],self.should,detail]
+ end
+
+ return :inode_changed
+ end
+ end
+ end
+end
+
+# $Id$
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index 4308291fa..b98764f48 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -6,6 +6,7 @@
module Puppet
class State
+ # Handle whether the service is started at boot time.
class ServiceEnabled < State
@doc = "Whether a service should be enabled to start at boot.
**true**/*false*/*runlevel*"
@@ -15,17 +16,17 @@ module Puppet
@is = @parent.enabled?
end
- def should=(should)
+ def shouldprocess(should)
case should
- when true: @should = :enabled
- when false: @should = :disabled
+ when true: return :enabled
+ when false: return :disabled
else
raise Puppet::Error, "Invalid 'enabled' value %s" % should
end
end
def sync
- case @should
+ case self.should
when :enabled
unless @parent.respond_to?(:enable)
raise Puppet::Error, "Service %s does not support enabling"
@@ -43,13 +44,12 @@ module Puppet
end
end
+ # Handle whether the service should actually be running right now.
class ServiceRunning < State
@doc = "Whether a service should be running. **true**/*false*"
@name = :running
- # this whole thing is annoying
- # i should probably just be using booleans, but for now, i'm not...
- def should=(should)
+ def shouldprocess(should)
case should
when false,0,"0", "stopped", :stopped:
should = :stopped
@@ -61,7 +61,7 @@ module Puppet
should = 0
end
Puppet.debug "Service should is %s" % should
- @should = should
+ return should
end
def retrieve
@@ -72,21 +72,21 @@ module Puppet
def sync
event = nil
- if @should == :running
+ case self.should
+ when :running
@parent.start
event = :service_started
- elsif @should == :stopped
+ when :stopped
@parent.stop
event = :service_stopped
else
Puppet.debug "Not running '%s' and shouldn't be running" %
self
end
-
- return event
end
end
end
+
class Type
class Service < Type
attr_reader :stat
diff --git a/lib/puppet/type/state.rb b/lib/puppet/type/state.rb
index 0d5d84b6f..7f74f7344 100644
--- a/lib/puppet/type/state.rb
+++ b/lib/puppet/type/state.rb
@@ -1,63 +1,26 @@
-#!/usr/local/bin/ruby -w
-
-# $Id$
+# The virtual base class for states, which are the self-contained building
+# blocks for actually doing work on the system.
require 'puppet'
require 'puppet/element'
require 'puppet/statechange'
-#---------------------------------------------------------------
-# this is a virtual base class for states
-# states are self-contained building blocks for objects
-
-# States can currently only be used for comparing a virtual "should" value
-# against the real state of the system. For instance, you could verify that
-# a file's owner is what you want, but you could not create two file objects
-# and use these methods to verify that they have the same owner
module Puppet
class State < Puppet::Element
- attr_accessor :is, :should, :parent
+ attr_accessor :is, :parent
+
+ # 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 :should, :shouldorig
@virtual = true
class << self
attr_accessor :unmanaged
+ attr_reader :name
end
- #---------------------------------------------------------------
- # which event gets generated if this state change happens; not currently
- # called
- def self.generates
- return @event
- end
- #---------------------------------------------------------------
-
- #---------------------------------------------------------------
- # every state class must tell us what its name will be (as a symbol)
- # this determines how we will refer to the state during usage
- # e.g., the Owner state for Files might say its name is :owner;
- # this means that we can say "file[:owner] = 'yayness'"
- def self.name
- return @name
- end
- #---------------------------------------------------------------
-
- #---------------------------------------------------------------
- # if we're not in sync, return a statechange capable of putting us
- # in sync
- #def evaluate
- # #debug "evaluating %s" % self
- # self.retrieve
- # if self.insync?
- # #debug "%s is in sync" % self
- # return nil
- # else
- # return Puppet::StateChange.new(self)
- # end
- #end
- #---------------------------------------------------------------
-
- #---------------------------------------------------------------
# initialize our state
def initialize(hash)
@is = nil
@@ -75,23 +38,35 @@ class State < Puppet::Element
self.is = hash[:is]
end
end
- #---------------------------------------------------------------
# Determine whether the state is in-sync or not. If @should is
# not defined or is set to a non-true value, then we do not have
# a valid value for it and thus consider the state to be in-sync
- # since we cannot fix it.
+ # since we cannot fix it. Otherwise, we expect our should value
+ # to be an array, and if @is matches any of those values, then
+ # we consider it to be in-sync.
def insync?
#debug "%s value is '%s', should be '%s'" %
# [self,self.is.inspect,self.should.inspect]
unless defined? @should and @should
return true
end
- self.is == self.should
+
+ unless @should.is_a?(Array)
+ raise Puppet::DevError, "%s's should is not array" % self.class.name
+ end
+
+ # Look for a matching value
+ @should.each { |val|
+ if @is == val
+ return true
+ end
+ }
+
+ # otherwise, return false
+ return false
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# each state class must define the name() method, and state instances
# do not change that name
# this implicitly means that a given object can only have one state
@@ -99,9 +74,7 @@ class State < Puppet::Element
def name
return self.class.name
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# for testing whether we should actually do anything
def noop
unless defined? @noop
@@ -111,18 +84,37 @@ class State < Puppet::Element
#debug "noop is %s" % tmp
return tmp
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return the full path to us, for logging and rollback; not currently
# used
def path
return [@parent.path, self.name].flatten
end
- #---------------------------------------------------------------
+ # Only return the first value
+ def should
+ return @should[0]
+ end
+
+ # Set the should value.
+ def should=(values)
+ unless values.is_a?(Array)
+ values = [values]
+ end
+
+ @shouldorig = values
- #---------------------------------------------------------------
+ if self.respond_to?(:shouldprocess)
+ @should = values.collect { |val|
+ self.shouldprocess(val)
+ }
+ else
+ @should = values
+ end
+ end
+
+
+ # How should a state change be printed as a string?
def change_to_s
if @is == :notfound
return "%s: defined '%s' as '%s'" %
@@ -135,8 +127,7 @@ class State < Puppet::Element
[self.parent, self.name, self.is_to_s, self.should_to_s]
end
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
@@ -148,12 +139,11 @@ class State < Puppet::Element
def should_to_s
@should
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def to_s
return "%s(%s)" % [@parent.name,self.name]
end
- #---------------------------------------------------------------
end
end
+
+# $Id$
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index b88bc5c5a..9db7173a7 100755
--- a/lib/puppet/type/user.rb
+++ b/lib/puppet/type/user.rb
@@ -33,7 +33,7 @@ module Puppet
return highest + 1
end
- def should=(value)
+ def shouldprocess(value)
case value
when String
if value =~ /^[-0-9]+$/
@@ -49,7 +49,7 @@ module Puppet
end
end
- @should = value
+ return value
end
end
@@ -63,7 +63,7 @@ module Puppet
:gid
end
- def should=(gid)
+ def shouldprocess(gid)
method = :getgrgid
case gid
when String
@@ -77,8 +77,7 @@ module Puppet
raise Puppet::DevError, "Invalid GID %s" % gid
end
# these are treated specially by sync()
- @should = gid
- return
+ return gid
end
# FIXME this should really check to see if we already have a
@@ -92,7 +91,7 @@ module Puppet
end
Puppet.notice "setting gid to %s" % ginfo.gid.inspect
- @should = ginfo.gid
+ return ginfo.gid
end
end
diff --git a/test/certmgr/tc_certmgr.rb b/test/certmgr/tc_certmgr.rb
index b67ff920d..ec1cb62c4 100755
--- a/test/certmgr/tc_certmgr.rb
+++ b/test/certmgr/tc_certmgr.rb
@@ -221,7 +221,7 @@ class TestCertMgr < Test::Unit::TestCase
def test_interactiveca
ca = nil
Puppet[:ssldir] = "/tmp/puppetinteractivecatest"
- @@tmpfiles.push Puppet[:ssldir]
+ @@tmpfiles << Puppet[:ssldir]
assert_nothing_raised {
ca = Puppet::SSLCertificates::CA.new
diff --git a/test/puppettest.rb b/test/puppettest.rb
index f18675549..6b91f1049 100644
--- a/test/puppettest.rb
+++ b/test/puppettest.rb
@@ -1,4 +1,3 @@
-# $Id$
require 'test/unit'
libdir = File.join(File.dirname(__FILE__), '../lib')
@@ -360,7 +359,12 @@ class FileTesting < TestPuppet
}
tolist = file_list(todir).sort
- assert_equal(fromlist,tolist)
+ fromlist.sort.zip(tolist.sort).each { |a,b|
+ assert_equal(a, b,
+ "Fromfile %s with length %s does not match tofile %s with length %s" %
+ [a, fromlist.length, b, tolist.length])
+ }
+ #assert_equal(fromlist,tolist)
# and then do some verification that the files are actually set up
# the same
@@ -404,12 +408,14 @@ class FileTesting < TestPuppet
end
def delete_random_files(dir)
+ deleted = []
random_files(dir) { |file|
stat = File.stat(file)
begin
if stat.ftype == "directory"
false
else
+ deleted << file
File.unlink(file)
true
end
@@ -419,6 +425,8 @@ class FileTesting < TestPuppet
false
end
}
+
+ return deleted
end
def add_random_files(dir)
@@ -549,3 +557,5 @@ def failers
yield file
}
end
+
+# $Id$
diff --git a/test/server/tc_bucket.rb b/test/server/tc_bucket.rb
index 8a7e71511..49f01287a 100644
--- a/test/server/tc_bucket.rb
+++ b/test/server/tc_bucket.rb
@@ -196,6 +196,7 @@ class TestBucket < ServerTest
files = filelist()
tmpdir = File.join(tmpdir(),"tmpfiledir")
+ @@tmpfiles << tmpdir
FileUtils.mkdir_p(tmpdir)
Puppet[:autosign] = true
diff --git a/test/server/tc_master.rb b/test/server/tc_master.rb
index 4fb8df8b2..f4d5d967b 100644
--- a/test/server/tc_master.rb
+++ b/test/server/tc_master.rb
@@ -105,6 +105,7 @@ class TestMaster < ServerTest
manifest = mktestmanifest()
file2 = @createdfile + "2"
+ @@tmpfiles << file2
client = master = nil
assert_nothing_raised() {
diff --git a/test/types/tc_basic.rb b/test/types/tc_basic.rb
index f0257fef0..6ba91f076 100644
--- a/test/types/tc_basic.rb
+++ b/test/types/tc_basic.rb
@@ -5,15 +5,15 @@ if __FILE__ == $0
end
require 'puppet'
+require 'puppettest'
require 'test/unit'
-# $Id$
-
-class TestBasic < Test::Unit::TestCase
+class TestBasic < TestPuppet
# hmmm
# this is complicated, because we store references to the created
# objects in a central store
def setup
+ super
@component = nil
@configfile = nil
@sleeper = nil
@@ -29,7 +29,7 @@ class TestBasic < Test::Unit::TestCase
assert_nothing_raised() {
@filepath = "/tmp/testfile"
- system("rm -f %s" % @filepath)
+ @@tmpfiles << @filepath
@configfile = Puppet::Type::PFile.create(
:path => @filepath,
:create => true,
@@ -55,11 +55,6 @@ class TestBasic < Test::Unit::TestCase
#puts "ConfigFile is %s, id %s" % [@configfile, @configfile.object_id]
end
- def teardown
- Puppet::Type.allclear
- system("rm -f %s" % @filepath)
- end
-
def test_name_calls
[@sleeper,@configfile].each { |obj|
Puppet.debug "obj is %s" % obj
@@ -118,3 +113,5 @@ class TestBasic < Test::Unit::TestCase
}
end
end
+
+# $Id$
diff --git a/test/types/tc_file.rb b/test/types/tc_file.rb
index 8b19dc670..ec357dcc0 100644
--- a/test/types/tc_file.rb
+++ b/test/types/tc_file.rb
@@ -1,8 +1,7 @@
if __FILE__ == $0
$:.unshift '..'
$:.unshift '../../lib'
- $:.unshift "../../../../language/trunk/lib"
- $puppetbase = "../../../../language/trunk"
+ $puppetbase = "../.."
end
require 'puppet'
@@ -10,8 +9,6 @@ require 'test/unit'
require 'fileutils'
require 'puppettest'
-# $Id$
-
class TestFile < FileTesting
# hmmm
# this is complicated, because we store references to the created
@@ -500,3 +497,5 @@ class TestFile < FileTesting
}
end
end
+
+# $Id$
diff --git a/test/types/tc_filebucket.rb b/test/types/tc_filebucket.rb
index 6c57c8dab..a8ba7a8c3 100755
--- a/test/types/tc_filebucket.rb
+++ b/test/types/tc_filebucket.rb
@@ -125,6 +125,7 @@ class TestFileBucket < FileTesting
}
opath = "/tmp/anotherbuckettest"
+ @@tmpfiles << opath
system("cp /etc/passwd %s" % opath)
origmd5 = File.open(file.name) { |f| newmd5 = Digest::MD5.hexdigest(f.read) }
diff --git a/test/types/tc_filesources.rb b/test/types/tc_filesources.rb
index 0de4157bc..031e1b76e 100755
--- a/test/types/tc_filesources.rb
+++ b/test/types/tc_filesources.rb
@@ -11,28 +11,7 @@ require 'test/unit'
require 'fileutils'
require 'puppettest'
-# $Id$
-
class TestFileSources < FileTesting
-
-=begin
- def mkfile(hash)
- file = nil
- assert_nothing_raised {
- file = Puppet::Type::PFile.create(hash)
- }
- return file
- end
-
- def mktestfile
- # because luke's home directory is on nfs, it can't be used for testing
- # as root
- tmpfile = tempfile()
- File.open(tmpfile, "w") { |f| f.puts rand(100) }
- @@tmpfiles.push tmpfile
- mkfile(:name => tmpfile)
- end
-=end
def setup
begin
initstorage
@@ -83,10 +62,6 @@ class TestFileSources < FileTesting
child = file.newchild("childtest")
}
assert(child)
- assert_nothing_raised {
- child = file.newchild("childtest")
- }
- assert(child)
assert_raise(Puppet::DevError) {
file.newchild(File.join(path,"childtest"))
}
@@ -133,6 +108,7 @@ class TestFileSources < FileTesting
end
def recursive_source_test(fromdir, todir)
+ Puppet::Type.allclear
initstorage
tofile = nil
trans = nil
@@ -196,11 +172,15 @@ class TestFileSources < FileTesting
fromdir, todir = run_complex_sources
# then delete some files
assert(FileTest.exists?(todir))
- delete_random_files(todir)
+ missing_files = delete_random_files(todir)
# and run
recursive_source_test(fromdir, todir)
+ missing_files.each { |file|
+ assert(FileTest.exists?(file), "Deleted file %s is still missing" % file)
+ }
+
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
end
@@ -547,3 +527,5 @@ class TestFileSources < FileTesting
assert(!FileTest.exists?(name), "File with no source exists anyway")
end
end
+
+# $Id$