From 9d3aaad7085164e1cc3d665269f9c99c17a7c45a Mon Sep 17 00:00:00 2001 From: luke Date: Sun, 2 Oct 2005 01:56:38 +0000 Subject: removing the redundant pfile from the pfile state file names git-svn-id: https://reductivelabs.com/svn/puppet/trunk@713 980ebf18-57e1-0310-9a29-db15c13687c0 --- lib/puppet/type/pfile.rb | 14 +- lib/puppet/type/pfile/checksum.rb | 217 ++++++++++++++++++++++++++++ lib/puppet/type/pfile/create.rb | 87 +++++++++++ lib/puppet/type/pfile/group.rb | 115 +++++++++++++++ lib/puppet/type/pfile/mode.rb | 108 ++++++++++++++ lib/puppet/type/pfile/pfilechecksum.rb | 217 ---------------------------- lib/puppet/type/pfile/pfilecreate.rb | 87 ----------- lib/puppet/type/pfile/pfilegroup.rb | 115 --------------- lib/puppet/type/pfile/pfilemode.rb | 108 -------------- lib/puppet/type/pfile/pfilesource.rb | 257 --------------------------------- lib/puppet/type/pfile/pfiletype.rb | 31 ---- lib/puppet/type/pfile/pfileuid.rb | 103 ------------- lib/puppet/type/pfile/source.rb | 257 +++++++++++++++++++++++++++++++++ lib/puppet/type/pfile/type.rb | 31 ++++ lib/puppet/type/pfile/uid.rb | 103 +++++++++++++ 15 files changed, 925 insertions(+), 925 deletions(-) create mode 100755 lib/puppet/type/pfile/checksum.rb create mode 100755 lib/puppet/type/pfile/create.rb create mode 100755 lib/puppet/type/pfile/group.rb create mode 100755 lib/puppet/type/pfile/mode.rb delete mode 100755 lib/puppet/type/pfile/pfilechecksum.rb delete mode 100755 lib/puppet/type/pfile/pfilecreate.rb delete mode 100755 lib/puppet/type/pfile/pfilegroup.rb delete mode 100755 lib/puppet/type/pfile/pfilemode.rb delete mode 100755 lib/puppet/type/pfile/pfilesource.rb delete mode 100755 lib/puppet/type/pfile/pfiletype.rb delete mode 100755 lib/puppet/type/pfile/pfileuid.rb create mode 100755 lib/puppet/type/pfile/source.rb create mode 100755 lib/puppet/type/pfile/type.rb create mode 100755 lib/puppet/type/pfile/uid.rb (limited to 'lib/puppet') diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index c09ed5de9..2373ac8e4 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -8,13 +8,13 @@ require 'puppet/server/fileserver' # 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' +require 'puppet/type/pfile/type' +require 'puppet/type/pfile/create' +require 'puppet/type/pfile/checksum' +require 'puppet/type/pfile/uid' +require 'puppet/type/pfile/mode' +require 'puppet/type/pfile/group' +require 'puppet/type/pfile/source' module Puppet class Type diff --git a/lib/puppet/type/pfile/checksum.rb b/lib/puppet/type/pfile/checksum.rb new file mode 100755 index 000000000..8747cfeb5 --- /dev/null +++ b/lib/puppet/type/pfile/checksum.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/create.rb b/lib/puppet/type/pfile/create.rb new file mode 100755 index 000000000..f8b2f3818 --- /dev/null +++ b/lib/puppet/type/pfile/create.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/group.rb b/lib/puppet/type/pfile/group.rb new file mode 100755 index 000000000..f38860259 --- /dev/null +++ b/lib/puppet/type/pfile/group.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/mode.rb b/lib/puppet/type/pfile/mode.rb new file mode 100755 index 000000000..b432dc639 --- /dev/null +++ b/lib/puppet/type/pfile/mode.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/pfilechecksum.rb b/lib/puppet/type/pfile/pfilechecksum.rb deleted file mode 100755 index 8747cfeb5..000000000 --- a/lib/puppet/type/pfile/pfilechecksum.rb +++ /dev/null @@ -1,217 +0,0 @@ -# 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 deleted file mode 100755 index f8b2f3818..000000000 --- a/lib/puppet/type/pfile/pfilecreate.rb +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100755 index f38860259..000000000 --- a/lib/puppet/type/pfile/pfilegroup.rb +++ /dev/null @@ -1,115 +0,0 @@ -# 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 deleted file mode 100755 index b432dc639..000000000 --- a/lib/puppet/type/pfile/pfilemode.rb +++ /dev/null @@ -1,108 +0,0 @@ -# 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 deleted file mode 100755 index ec4f7107b..000000000 --- a/lib/puppet/type/pfile/pfilesource.rb +++ /dev/null @@ -1,257 +0,0 @@ -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 deleted file mode 100755 index 1d03634e7..000000000 --- a/lib/puppet/type/pfile/pfiletype.rb +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100755 index 176988eb1..000000000 --- a/lib/puppet/type/pfile/pfileuid.rb +++ /dev/null @@ -1,103 +0,0 @@ -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/pfile/source.rb b/lib/puppet/type/pfile/source.rb new file mode 100755 index 000000000..ec4f7107b --- /dev/null +++ b/lib/puppet/type/pfile/source.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/type.rb b/lib/puppet/type/pfile/type.rb new file mode 100755 index 000000000..1d03634e7 --- /dev/null +++ b/lib/puppet/type/pfile/type.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/uid.rb b/lib/puppet/type/pfile/uid.rb new file mode 100755 index 000000000..176988eb1 --- /dev/null +++ b/lib/puppet/type/pfile/uid.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$ -- cgit