diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-01-07 23:33:38 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-01-07 23:33:38 +0000 |
commit | 23f982ecda3fd74867d404b5e784f072db9a1cde (patch) | |
tree | 18a122eec695455c794caa554012fe1ee721ffa6 | |
parent | 1d739731b20a5dd10a190d783556d5c5a0275137 (diff) | |
download | puppet-23f982ecda3fd74867d404b5e784f072db9a1cde.tar.gz puppet-23f982ecda3fd74867d404b5e784f072db9a1cde.tar.xz puppet-23f982ecda3fd74867d404b5e784f072db9a1cde.zip |
Undoing the merge that happened in 785
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@786 980ebf18-57e1-0310-9a29-db15c13687c0
79 files changed, 3694 insertions, 4131 deletions
@@ -35,12 +35,8 @@ end DOWNDIR = "/export/docroots/reductivelabs.com/htdocs/downloads" -if ENV['HOSTS'] - TESTHOSTS = ENV['HOSTS'].split(/\s+/) -else - TESTHOSTS = %w{fedora1 rh3a kirby culain} -end -#TESTHOSTS = %w{sol10b} +#TESTHOSTS = %w{sol10b fedora1 rh3a} +TESTHOSTS = %w{sol10b} # The default task is run if rake is given no explicit arguments. @@ -344,9 +340,8 @@ task :hosttest do out = "" TESTHOSTS.each { |host| puts "testing %s" % host - cwd = Dir.getwd #out += %x{ssh #{host} 'cd puppet/test; sudo ./test' 2>&1} - sh %{ssh #{host} 'cd #{cwd}/test; sudo ./test' 2>&1} + sh %{ssh #{host} 'cd puppet/test; sudo ./test' 2>&1} } #IO.popen("mail -s 'Puppet Test Results' luke@madstop.com") do |m| diff --git a/examples/root/etc/init.d/sleeper b/examples/root/etc/init.d/sleeper index 121d19940..e7f5d3e30 100755 --- a/examples/root/etc/init.d/sleeper +++ b/examples/root/etc/init.d/sleeper @@ -15,8 +15,7 @@ fi function start { - cd $path - ./sleeper + sleeper } function stop diff --git a/lib/puppet.rb b/lib/puppet.rb index 0795cb9d6..5d0a3c579 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -239,25 +239,6 @@ PUPPETVERSION = '0.9.4' return true end end - # Create a new type - def self.newtype(name, parent = nil, &block) - parent ||= Puppet::Type - Puppet::Util.symbolize(name) - t = Class.new(parent) do - @name = name - end - t.class_eval(&block) - @types ||= {} - @types[name] = t - end - - # Retrieve a type by name - def self.type(name) - unless defined? @types - return nil - end - return @types[name] - end end require 'puppet/util' diff --git a/lib/puppet/client.rb b/lib/puppet/client.rb index 80b9fe30f..56e78349a 100644 --- a/lib/puppet/client.rb +++ b/lib/puppet/client.rb @@ -20,7 +20,6 @@ begin require 'xmlrpc/server' rescue LoadError => detail $noclientnetworking = detail - raise Puppet::Error, "You must have the Ruby XMLRPC, CGI, and Webrick libraries installed" end module Puppet @@ -414,17 +413,9 @@ module Puppet if tmp = @driver.getfile(sum) newcontents = Base64.decode64(tmp) newsum = Digest::MD5.hexdigest(newcontents) - changed = nil - unless FileTest.writable?(file) - changed = File.stat(file).mode - File.chmod(changed | 0200, file) - end File.open(file,File::WRONLY|File::TRUNC) { |of| of.print(newcontents) } - if changed - File.chmod(changed, file) - end else Puppet.err "Could not find file with checksum %s" % sum return nil diff --git a/lib/puppet/element.rb b/lib/puppet/element.rb index 7e499567a..4d1ad8bac 100644 --- a/lib/puppet/element.rb +++ b/lib/puppet/element.rb @@ -40,7 +40,7 @@ class Puppet::Element def path unless defined? @path if defined? @parent and @parent - if self.is_a?(Puppet.type(:component)) + if self.is_a?(Puppet::Type::Component) @path = [@parent.path, self.name] else @path = [@parent.path, self.class.name.to_s + "=" + self.name] @@ -54,10 +54,10 @@ class Puppet::Element else # We assume that if we don't have a parent that we should not # cache the path - if self.is_a?(Puppet.type(:component)) + if self.is_a?(Puppet::Type::Component) @path = [self.name] else - @path = [self.class.name.to_s + "=" + self.name.to_s] + @path = [self.class.name.to_s + "=" + self.name] end end end diff --git a/lib/puppet/event.rb b/lib/puppet/event.rb index a7070bb3e..e2c364194 100644 --- a/lib/puppet/event.rb +++ b/lib/puppet/event.rb @@ -192,7 +192,7 @@ module Puppet end if transaction.triggered?(self.target, @callback) > 0 - self.target.info "already applied %s" % [@callback] + Puppet.debug "%s has already run" % self else # We need to call the method, so that it gets retrieved # as a real object. @@ -201,7 +201,6 @@ module Puppet # [@source,@event,@method,target] begin if target.respond_to?(@callback) - target.log "triggering %s" % @callback event = target.send(@callback) else Puppet.debug( @@ -241,6 +240,14 @@ module Puppet @event = args[:event] @source = args[:source] @transaction = args[:transaction] + + #Puppet.info "%s: %s(%s)" % + #Puppet.info "%s: %s changed from %s to %s" % + # [@object,@state.name, @state.is,@state.should] + + # initially, just stuff all instances into a central bucket + # to be handled as a batch + #@@events.push self end def to_s diff --git a/lib/puppet/log.rb b/lib/puppet/log.rb index 7d4b750c7..9fff07225 100644 --- a/lib/puppet/log.rb +++ b/lib/puppet/log.rb @@ -67,12 +67,6 @@ module Puppet # :nodoc: # Create a new log message. The primary role of this method is to # avoid creating log messages below the loglevel. def Log.create(hash) - unless hash.include?(:level) - raise Puppet::DevError, "Logs require a level" - end - unless @levels.index(hash[:level]) - raise Puppet::DevError, "Invalid log level %s" % hash[:level] - end if @levels.index(hash[:level]) >= @loglevel return Puppet::Log.new(hash) else @@ -165,9 +159,6 @@ module Puppet # :nodoc: # It's worth noting that there's a potential for a loop here, if # the machine somehow gets the destination set as itself. def Log.newmessage(msg) - if @levels.index(msg.level) < @loglevel - return - end @destinations.each { |type, dest| case dest when Module # This is the Syslog module @@ -239,10 +230,6 @@ module Puppet # :nodoc: } end - def Log.sendlevel?(level) - @levels.index(level) >= @loglevel - end - # Reopen all of our logs. def Log.reopen types = @destinations.keys @@ -286,10 +273,6 @@ module Puppet # :nodoc: raise Puppet::DevError, "Level is not a string or symbol: #{args[:level].class}" end - - # Just return unless we're actually at a level we should send - #return unless self.class.sendlevel?(@level) - @message = args[:message].to_s @time = Time.now # this should include the host name, and probly lots of other diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb deleted file mode 100644 index d2656b766..000000000 --- a/lib/puppet/parameter.rb +++ /dev/null @@ -1,196 +0,0 @@ -module Puppet - class Parameter < Puppet::Element - class << self - attr_reader :validater, :munger, :name, :default - attr_accessor :ismetaparameter, :element - - # This means that 'nil' is an invalid default value. - def defaultto(value = nil, &block) - if block - @default = block - else - @default = value - end - end - - # Store documentation for this parameter. - def desc(str) - @doc = str - end - - # This is how we munge the value. Basically, this is our - # opportunity to convert the value from one form into another. - def munge(&block) - # I need to wrap the unsafe version in begin/rescue statements, - # but if I directly call the block then it gets bound to the - # class's context, not the instance's, thus the two methods, - # instead of just one. - define_method(:unsafe_munge, &block) - - define_method(:munge) do |*args| - begin - unsafe_munge(*args) - rescue Puppet::Error => detail - Puppet.debug "Reraising %s" % detail - raise - rescue => detail - raise Puppet::DevError, "Munging failed for class %s: %s" % - [self.name, detail] - end - end - #@munger = block - end - - def inspect - "Parameter(#{self.name})" - end - - # Mark whether we're the namevar. - def isnamevar - @isnamevar = true - @required = true - end - - # Is this parameter the namevar? Defaults to false. - def isnamevar? - if defined? @isnamevar - return @isnamevar - else - return false - end - end - - # This parameter is required. - def isrequired - @required = true - end - - # Is this parameter required? Defaults to false. - def required? - if defined? @required - return @required - else - return false - end - end - - def to_s - if self.ismetaparameter - "Puppet::Type::" + @name.to_s.capitalize - else - self.element.to_s + @name.to_s.capitalize - end - end - - # Verify that we got a good value - def validate(&block) - #@validater = block - define_method(:unsafe_validate, &block) - - define_method(:validate) do |*args| - begin - unsafe_validate(*args) - rescue ArgumentError, Puppet::Error, TypeError - raise - rescue => detail - raise Puppet::DevError, - "Validate method failed for class %s: %s" % - [self.name, detail] - end - end - end - end - - # Just a simple method to proxy instance methods to class methods - def self.proxymethods(*values) - values.each { |val| - eval "def #{val}; self.class.#{val}; end" - } - end - - # And then define one of these proxies for each method in our - # ParamHandler class. - proxymethods("required?", "default", "isnamevar?") - - attr_accessor :parent - - # This doesn't work, because the instance_eval doesn't bind the inner block - # only the outer one. -# def munge(value) -# if munger = self.class.munger -# return @parent.instance_eval { -# munger.call(value) -# } -# else -# return value -# end -# end -# -# def validate(value) -# if validater = self.class.validater -# return @parent.instance_eval { -# validater.call(value) -# } -# end -# end - - def default - default = self.class.default - if default.is_a?(Proc) - val = self.instance_eval(&default) - return val - else - return default - end - end - - # This should only be called for parameters, but go ahead and make - # it possible to call for states, too. - def value - if self.is_a?(Puppet::State) - return self.should - else - return @value - end - end - - # Store the value provided. All of the checking should possibly be - # late-binding (e.g., users might not exist when the value is assigned - # but might when it is asked for). - def value=(value) - # If we're a state, just hand the processing off to the should method. - if self.is_a?(Puppet::State) - return self.should = value - end - if respond_to?(:validate) - validate(value) - end - - if respond_to?(:munge) - value = munge(value) - end - @value = value - end - - def to_s - "%s => %s" % [self.class.name, self.value] - end - - def inspect - s = "Parameter(%s = %s" % [self.name, self.value || "nil"] - if defined? @parent - s += ", @parent = %s)" % @parent - else - s += ")" - end - end - - def name - self.class.name - end - - def to_s - s = "Parameter(%s)" % self.name - end - end -end diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 193f85eb1..dd56c109a 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -545,7 +545,7 @@ module Puppet raise Puppet::DevError, detail.to_s end next if pname == "name" # always allow these - unless type.validattr?(pname) + unless type.validarg?(pname) error = Puppet::ParseError.new( "Invalid parameter '%s' for type '%s'" % [pname,type.name] diff --git a/lib/puppet/server/fileserver.rb b/lib/puppet/server/fileserver.rb index 9130b3df5..92bc129ec 100755 --- a/lib/puppet/server/fileserver.rb +++ b/lib/puppet/server/fileserver.rb @@ -28,8 +28,8 @@ class Server end obj = nil - unless obj = Puppet.type(:file)[dir] - obj = Puppet.type(:file).create( + unless obj = Puppet::Type::PFile[dir] + obj = Puppet::Type::PFile.create( :name => dir, :check => CHECKPARAMS ) @@ -87,7 +87,7 @@ class Server # Deal with ignore parameters. def handleignore(children, path, ignore) - ignore.value.each { |ignore| + ignore.each { |ignore| Dir.glob(File.join(path,ignore), File::FNM_DOTMATCH) { |match| children.delete(File.basename(match)) } diff --git a/lib/puppet/server/logger.rb b/lib/puppet/server/logger.rb index d5feb0320..0ee2d75f0 100755 --- a/lib/puppet/server/logger.rb +++ b/lib/puppet/server/logger.rb @@ -10,11 +10,6 @@ class Server # :nodoc: # accept a log message from a client, and route it accordingly def addlog(message, client = nil, clientip = nil) - unless message - raise Puppet::DevError, "Did not receive message" - end - - Puppet.info message.inspect # if the client is set, then we're not local if client begin @@ -27,10 +22,6 @@ class Server # :nodoc: end end - unless message - raise Puppet::DevError, "Could not resurrect message" - end - # Mark it as remote, so it's not sent to syslog message.remote = true diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index 9196da61b..d543c5200 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -1,19 +1,14 @@ # The library for manipulating SSL certs. require 'puppet' - -begin - require 'openssl' -rescue LoadError - raise Puppet::Error, "You must have the Ruby openssl library installed" -end +require 'openssl' module Puppet module SSLCertificates def self.mkdir(dir) # this is all a bunch of stupid hackery unless FileTest.exists?(dir) - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "certdir creation" ) path = [''] diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 888c4580d..47b18986e 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -160,6 +160,7 @@ class Transaction #--------------------------------------------------------------- def triggered(object, method) + Puppet.notice "Triggered %s" % method @triggered[object][method] += 1 #@triggerevents << ("%s_%sed" % [object.class.name.to_s, method.to_s]).intern end @@ -167,6 +168,7 @@ class Transaction #--------------------------------------------------------------- def triggered?(object, method) + Puppet.notice "Looking for triggered %s" % method @triggered[object][method] end #--------------------------------------------------------------- diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb index e81401c41..ffa751eb6 100644 --- a/lib/puppet/transportable.rb +++ b/lib/puppet/transportable.rb @@ -102,7 +102,7 @@ module Puppet if parent hash[:parent] = parent end - container = Puppet.type(:component).create(hash) + container = Puppet::Type::Component.create(hash) if parent parent.push container diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 26a6823ba..a71104fc0 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -4,21 +4,15 @@ require 'puppet/element' require 'puppet/event' require 'puppet/metric' require 'puppet/type/state' -require 'puppet/parameter' -require 'puppet/util' # see the bottom of the file for the rest of the inclusions module Puppet # :nodoc: +# This class is the abstract base class for the mechanism for organizing +# work. No work is actually done by this class or its subclasses; rather, +# the subclasses include states which do the actual work. +# See state.rb for how work is actually done. class Type < Puppet::Element - # Types (which map to elements in the languages) are entirely composed of - # attribute value pairs. Generally, Puppet calls any of these things an - # 'attribute', but these attributes always take one of three specific - # forms: parameters, metaparams, or states. - - # In naming methods, I have tried to consistently name the method so - # that it is clear whether it operates on all attributes (thus has 'attr' in - # the method name, or whether it operates on a specific type of attributes. - attr_accessor :children, :parent + attr_accessor :children, :parameters, :parent attr_accessor :file, :line, :tags attr_writer :implicit @@ -119,14 +113,6 @@ class Type < Puppet::Element # the Type class attribute accessors class << self attr_reader :name, :namevar, :states, :parameters - - def inspect - "Type(%s)" % self.name - end - - def to_s - self.inspect - end end # Create @@typehash from @@typeary. This is meant to be run @@ -147,12 +133,7 @@ class Type < Puppet::Element # iterate across all of the subclasses of Type def self.eachtype - @@typeary.each do |type| - # Only consider types that have names - if type.name - yield type - end - end + @@typeary.each { |type| yield type } end # The work that gets done for every subclass of Type @@ -334,126 +315,17 @@ class Type < Puppet::Element } end - # Find the namevar - def self.namevar - unless defined? @namevar - @namevar = @parameters.find { |name, param| - param.isnamevar? - unless param - raise Puppet::DevError, "huh? %s" % name - end - }[0] - end - @namevar - end - - # Copy an existing class parameter. This allows other types to avoid - # duplicating a parameter definition, and is mostly used by subclasses - # of the File class. - def self.copyparam(klass, name) - param = klass.attrclass(name) - - unless param - raise Puppet::DevError, "Class %s has no param %s" % [klass, name] - end - @parameters ||= [] - @parameters << param - - @paramhash ||= {} - @parameters.each { |p| @paramhash[name] = p } - - if param.isnamevar? - @namevar = param.name - end - end - - # Create a new metaparam. Requires a block and a name, stores it in the - # @parameters array, and does some basic checking on it. - def self.newmetaparam(name, &block) - Puppet::Util.symbolize(name) - param = Class.new(Puppet::Parameter) do - @name = name - end - param.ismetaparameter - param.class_eval(&block) - @@metaparams ||= [] - @@metaparams << param - - @@metaparamhash ||= {} - @@metaparams.each { |p| @@metaparamhash[name] = p } - end - - # Create a new parameter. Requires a block and a name, stores it in the - # @parameters array, and does some basic checking on it. - def self.newparam(name, &block) - Puppet::Util.symbolize(name) - param = Class.new(Puppet::Parameter) do - @name = name - end - param.element = self - param.class_eval(&block) - @parameters ||= [] - @parameters << param - - @paramhash ||= {} - @parameters.each { |p| @paramhash[name] = p } - - if param.isnamevar? - @namevar = param.name - end - end - - # Create a new state. - def self.newstate(name, parent = nil, &block) - parent ||= Puppet::State - if @validstates.include?(name) - raise Puppet::DevError, "Class %s already has a state named %s" % - [self.name, name] - end - s = Class.new(parent) do - @name = name - end - s.class_eval(&block) - @states ||= [] - @states << s - @validstates[name] = s - - return s - end - - # Return the parameter names - def self.parameters - @parameters.collect { |klass| klass.name } - end - - # Find the metaparameter class associated with a given metaparameter name. - def self.metaparamclass(name) - @@metaparamhash[name] - end - - # Find the parameter class associated with a given parameter name. - def self.paramclass(name) - @paramhash[name] - end - - # Find the class associated with any given attribute. - def self.attrclass(name) - case self.attrtype(name) - when :param: @paramhash[name] - when :meta: @@metaparamhash[name] - when :state: @validstates[name] - end - end - - def self.to_s - "Puppet::Type::" + @name.to_s.capitalize - end - - # Create a block to validate that our object is set up entirely. This will - # be run before the object is operated on. - def self.validate(&block) - define_method(:validate, &block) - #@validate = block + # set the parameters for a type; probably only used by FileRecord + # objects + def self.parameters=(params) + Puppet.debug "setting parameters to [%s]" % params.join(" ") + @parameters = params.collect { |param| + if param.class == Symbol + param + else + param.intern + end + } end # does the name reflect a valid state? @@ -490,43 +362,14 @@ class Type < Puppet::Element unless defined? @parameters raise Puppet::DevError, "Class %s has not defined parameters" % self end - if @paramhash.include?(name) or @@metaparamhash.include?(name) + if @parameters.include?(name) or @@metaparams.include?(name) return true else return false end end - # What type of parameter are we dealing with? - def self.attrtype(name) - case - when @paramhash.include?(name): return :param - when @@metaparamhash.include?(name): return :meta - when @validstates.include?(name): return :state - else - raise Puppet::DevError, "Invalid parameter %s" % [name] - end - end - - # All parameters, in the appropriate order. The namevar comes first, - # then the states, then the params and metaparams in the order they - # were specified in the files. - def self.allattrs - # now get all of the arguments, in a specific order - order = [self.namevar] - order << [self.states.collect { |state| state.name }, - self.parameters, - self.metaparams].flatten.reject { |param| - # we don't want our namevar in there multiple times - param == self.namevar - } - - order.flatten! - - return order - end - - def self.validattr?(name) + def self.validarg?(name) if name.is_a?(String) name = name.intern end @@ -558,26 +401,18 @@ class Type < Puppet::Element end elsif Puppet::Type.metaparam?(name) if @metaparams.include?(name) - return @metaparams[name].value + return @metaparams[name] else - if default = self.class.metaattrclass(name).default - return default - else - return nil - end + return nil end elsif self.class.validparameter?(name) if @parameters.include?(name) return @parameters[name] else - if default = self.class.attrclass(name).default - return default - else - return nil - end + return nil end else - raise TypeError.new("Invalid parameter %s(%s)" % [name, name.inspect]) + raise TypeError.new("Invalid parameter %s" % [name]) end end @@ -595,9 +430,10 @@ class Type < Puppet::Element if value.nil? raise Puppet::Error.new("Got nil value for %s" % name) end - if Puppet::Type.metaparam?(name) - self.newmetaparam(self.class.metaparamclass(name), value) + @parameters[name] = value + # call the metaparam method + self.send(("meta" + name.id2name + "="),value) elsif stateklass = self.class.validstate?(name) if value.is_a?(Puppet::State) self.debug "'%s' got handed a state for '%s'" % [self,name] @@ -616,7 +452,13 @@ class Type < Puppet::Element end elsif self.class.validparameter?(name) # if they've got a method to handle the parameter, then do it that way - self.newparam(self.class.attrclass(name), value) + method = "param" + name.id2name + "=" + if self.respond_to?(method) + self.send(method,value) + else + # else just set it + @parameters[name] = value + end else raise Puppet::Error, "Invalid parameter %s" % [name] end @@ -692,7 +534,7 @@ class Type < Puppet::Element # create a log at specified level def log(msg) Puppet::Log.create( - :level => @metaparams[:loglevel].value, + :level => @metaparams[:loglevel], :message => msg, :source => self ) @@ -716,52 +558,10 @@ class Type < Puppet::Element end end - # Create a new parameter. - def newparam(klass, value = nil) - newattr(:param, klass, value) - end - - # Create a new parameter or metaparameter. We'll leave the calling - # method to store it appropriately. - def newmetaparam(klass, value = nil) - newattr(:meta, klass, value) - end - - # The base function that the others wrap. - def newattr(type, klass, value = nil) - # This should probably be a bit, um, different, but... - if type == :state - return newstate(klass) - end - param = klass.new - param.parent = self - if value - param.value = value - end - - case type - when :meta - @metaparams[klass.name] = param - when :param - @parameters[klass.name] = param - else - raise Puppet::DevError, "Invalid param type %s" % type - end - - return param - end - # create a new state def newstate(name, hash = {}) - stateklass = nil - if name.is_a?(Class) - stateklass = name - name = stateklass.name - else - stateklass = self.class.validstate?(name) - unless stateklass - raise Puppet::Error, "Invalid state %s" % name - end + unless stateklass = self.class.validstate?(name) + raise Puppet::Error, "Invalid parameter %s" % name end if @states.include?(name) hash.each { |var,value| @@ -775,7 +575,7 @@ class Type < Puppet::Element # make sure the state doesn't have any errors newstate = stateklass.new(hash) @states[name] = newstate - return newstate + return true rescue Puppet::Error => detail # the state failed, so just ignore it self.warning "State %s failed: %s" % @@ -832,14 +632,6 @@ class Type < Puppet::Element end end - # Is the named state defined? - def statedefined?(name) - unless name.is_a? Symbol - name = name.intern - end - return @states.include?(name) - end - # return an actual type by name; to return the value, use 'inst[name]' # FIXME this method should go away def state(name) @@ -990,9 +782,23 @@ class Type < Puppet::Element unless defined? @metaparams @metaparams = Hash.new(false) end + + #unless defined? @paramdoc + # @paramdoc = Hash.new { |hash,key| + # if key.is_a?(String) + # key = key.intern + # end + # if hash.include?(key) + # hash[key] + # else + # "Param Documentation for %s not found" % key + # end + # } + #end # set defalts @noop = false + @metaparams[:loglevel] = :notice # keeping stats for the total number of changes, and how many were # completely sync'ed # this isn't really sufficient either, because it adds lots of special cases @@ -1011,7 +817,16 @@ class Type < Puppet::Element hash = self.argclean(hash) - self.class.allattrs.each { |name| + # now get all of the arguments, in a specific order + order = [self.class.namevar] + order << [self.class.states.collect { |state| state.name }, + self.class.parameters, + self.class.eachmetaparam { |param| param }].flatten.reject { |param| + # we don't want our namevar in there multiple times + param == self.class.namevar + } + + order.flatten.each { |name| if hash.include?(name) begin self[name] = hash[name] @@ -1024,8 +839,6 @@ class Type < Puppet::Element end } - self.setdefaults - if hash.length > 0 self.debug hash.inspect raise Puppet::Error.new("Class %s does not accept argument(s) %s" % @@ -1035,40 +848,6 @@ class Type < Puppet::Element # add this object to the specific class's list of objects #puts caller self.class[self.name] = self - - if self.respond_to?(:validate) - self.validate - end - end - - # Is the specified parameter set? - def attrset?(type, attr) - case type - when :state: return @states.include?(attr) - when :param: return @parameters.include?(attr) - when :meta: return @metaparams.include?(attr) - else - raise Puppet::DevError, "Invalid set type %s" % [type] - end - end - - # For any parameters or states that have defaults and have not yet been - # set, set them now. - def setdefaults - self.class.allattrs.each { |attr| - type = self.class.attrtype(attr) - next if self.attrset?(type, attr) - - klass = self.class.attrclass(attr) - unless klass - raise Puppet::DevError, "Could not retrieve class for %s" % attr - end - if klass.default - obj = self.newattr(type, klass) - obj.value = obj.default - end - } - end # Merge new information with an existing object, checking for conflicts @@ -1124,7 +903,7 @@ class Type < Puppet::Element unless defined? @name and @name namevar = self.class.namevar if self.class.validparameter?(namevar) - @name = self[:name] + @name = @parameters[namevar] elsif self.class.validstate?(namevar) @name = self.should(namevar) else @@ -1134,7 +913,7 @@ class Type < Puppet::Element end unless @name - raise Puppet::DevError, "Could not find namevar '%s' for %s" % + raise Puppet::DevError, "Could not find name %s for %s" % [namevar, self.class.name] end @@ -1190,7 +969,7 @@ class Type < Puppet::Element # FIXME this method is essentially obviated, but it's still used by tests # and i don't feel like fixing it yet def sync - raise Puppet::DevError, "Type#sync called" + #raise Puppet::DevError, "Type#sync called" events = self.collect { |child| child.sync }.reject { |event| @@ -1331,8 +1110,10 @@ class Type < Puppet::Element # Meta-parameter methods: These methods deal with the results # of specifying metaparameters - def self.metaparams - @@metaparams.collect { |param| param.name } + def self.eachmetaparam + @@metaparams.each { |param| + yield param + } end # This just marks states that we definitely want to retrieve values @@ -1357,7 +1138,7 @@ class Type < Puppet::Element # Is the parameter in question a meta-parameter? def self.metaparam?(param) - @@metaparamhash.include?(param) + @@metaparams.include?(param) end # for each object we require, subscribe to all events that it @@ -1551,106 +1332,6 @@ class Type < Puppet::Element def self.metaparamdoc(metaparam) @@metaparamdoc[metaparam] end - - # Add all of the meta parameters. - newmetaparam(:onerror) do - desc "How to handle errors -- roll back innermost - transaction, roll back entire transaction, ignore, etc. Currently - non-functional." - end - - newmetaparam(:noop) do - desc "Boolean flag indicating whether work should actually - be done." - munge do |noop| - if noop == "true" or noop == true - return true - elsif noop == "false" or noop == false - return false - else - raise Puppet::Error.new("Invalid noop value '%s'" % noop) - end - end - end - - newmetaparam(:schedule) do - desc "On what schedule the object should be managed. - Currently non-functional." - end - - newmetaparam(:check) do - desc "States which should have their values retrieved - but which should not actually be modified. This is currently used - internally, but will eventually be used for querying." - - munge do |args| - unless args.is_a?(Array) - args = [args] - end - - unless defined? @parent - raise Puppet::DevError, "No parent for %s, %s?" % - [self.class, self.name] - end - - args.each { |state| - unless state.is_a?(Symbol) - state = state.intern - end - next if @parent.statedefined?(state) - - @parent.newstate(state) - } - end - end - # For each object we require, subscribe to all events that it generates. We - # might reduce the level of subscription eventually, but for now... - newmetaparam(:require) do - desc "One or more objects that this object depends on. - This is used purely for guaranteeing that changes to required objects - happen before the dependent object." - - munge do |requires| - @parent.handledepends(requires, :NONE, nil) - end - end - - # For each object we require, subscribe to all events that it generates. - # We might reduce the level of subscription eventually, but for now... - newmetaparam(:subscribe) do - desc "One or more objects that this object depends on. - Changes in the subscribed to objects result in the dependent objects being - refreshed (e.g., a service will get restarted)." - - munge do |requires| - @parent.handledepends(requires, :ALL_EVENTS, :refresh) - end - end - - newmetaparam(:loglevel) do - desc "Sets the level that information will be logged: - debug, info, verbose, notice, warning, err, alert, emerg or crit" - defaultto :notice - - validate do |loglevel| - if loglevel.is_a?(String) - loglevel = loglevel.intern - end - unless Puppet::Log.validlevel?(loglevel) - raise Puppet::Error, "Invalid log level %s" % loglevel - end - end - - munge do |loglevel| - if loglevel.is_a?(String) - loglevel = loglevel.intern - end - if loglevel == :verbose - loglevel = :info - end - loglevel - end - end end # Puppet::Type end diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb index 78ccb36da..c7b553b22 100644 --- a/lib/puppet/type/component.rb +++ b/lib/puppet/type/component.rb @@ -7,20 +7,15 @@ require 'puppet/type' require 'puppet/transaction' module Puppet - newtype(:component) do + class Type + class Component < Puppet::Type include Enumerable - newparam(:name) do - desc "The name of the component. Generally optional." - isnamevar - end - - newparam(:type) do - desc "The type that this component maps to. Generally some kind of - class from the language." + @name = :component + @namevar = :name - defaultto "component" - end + @states = [] + @parameters = [:name,:type] # topo sort functions def self.sort(objects) @@ -45,7 +40,7 @@ module Puppet self.recurse(req, inlist, list) } - if obj.is_a? self + if obj.is_a?(Puppet::Type::Component) obj.each { |child| self.recurse(child, inlist, list) } @@ -78,6 +73,11 @@ module Puppet # Initialize a new component def initialize(args) @children = [] + + # it makes sense to have a more reasonable default here than 'false' + unless args.include?(:type) or args.include?("type") + args[:type] = "component" + end super(args) end @@ -120,7 +120,6 @@ module Puppet @children.collect { |child| if child.respond_to?(:refresh) child.refresh - child.log "triggering %s" % :refresh end } end @@ -135,6 +134,7 @@ module Puppet return "component(%s)" % self.name end end + end end # $Id$ diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 9e10ae01b..e3bac17fc 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -1,3 +1,6 @@ +# A Puppet::Type class to manage cron jobs. Some abstraction is done, +# so that different platforms' versions of +crontab+ all work equivalently. + require 'etc' require 'facter' require 'puppet/type/state' @@ -13,7 +16,7 @@ module Puppet # writing. module CronType # Retrieve the uid of a user. This is duplication of code, but the unless - # I start using Puppet.type(:user) objects here, it's a much better design. + # I start using Puppet::Type::User objects here, it's a much better design. def self.uid(user) begin return Etc.getpwnam(user).uid @@ -84,16 +87,77 @@ module Puppet end end - # Model the actual cron jobs. Supports all of the normal cron job fields - # as parameters, with the 'command' as the single state. Also requires a - # completely symbolic 'name' paremeter, which gets written to the file - # and is used to manage the job. - newtype(:cron) do + class State + # This is Cron's single state. Somewhat uniquely, this state does not + # actually change anything -- it just calls +@parent.sync+, which writes + # out the whole cron tab for the user in question. There is no real way + # to change individual cron jobs without rewriting the entire cron file. + # + # Note that this means that managing many cron jobs for a given user + # could currently result in multiple write sessions for that user. + class CronCommand < Puppet::State + @name = :command + @doc = "The command to execute in the cron job. The environment + provided to the command varies by local system rules, and it is + best to always provide a fully qualified command. The user's + profile is not sourced when the command is run, so if the + user's environment is desired it should be sourced manually." + + # Normally this would retrieve the current value, but our state is not + # actually capable of doing so. The Cron class does the actual tab + # retrieval, so all this method does is default to :notfound for @is. + def retrieve + unless defined? @is and ! @is.nil? + @is = :notfound + end + end + + # Determine whether the cron job should be destroyed, and figure + # out which event to return. Finally, call @parent.sync to write the + # cron tab. + def sync + event = nil + if @is == :notfound + #@is = @should + event = :cron_created + # We're the first state, so if we're creating the job + # then sync all of the other states + @parent.eachstate { |state| + next if state == self + state.sync(true) + } + + @is = self.should + elsif self.should == :notfound + @parent.remove(true) + event = :cron_deleted + elsif self.insync? + return nil + else + @is = self.should + event = :cron_changed + end + + @parent.store + + return event + end + end + # A base class for all of the Cron parameters, since they all have # similar argument checking going on. class CronParam < Puppet::State class << self - attr_accessor :boundaries + attr_reader :checking + end + + def weekdays + %w{sunday monday tuesday wednesday thursday friday saturday} + end + + def months + %w{january february march april may june july + august september october november december} end # Normally this would retrieve the current value, but our state is not @@ -158,9 +222,6 @@ module Puppet # or the first three letters of the word. def alphacheck(value, ary) tmp = value.downcase - - # If they specified a shortened version of the name, then see - # if we can lengthen it (e.g., mon => monday). if tmp.length == 3 ary.each_with_index { |name, index| if name =~ /#{tmp}/i @@ -189,392 +250,353 @@ module Puppet # Requires the value, type, and bounds, and optionally supports # a boolean of whether to do alpha checking, and if so requires # the ary against which to do the checking. - munge do |value| - lower, upper = self.class.boundaries + def validate(value, lower, upper, arymethod = nil) retval = nil if num = numfix(value) retval = limitcheck(num, lower, upper) - elsif respond_to?(:alpha) - # If it has an alpha method defined, then we check - # to see if our value is in that list and if so we turn - # it into a number - retval = alphacheck(value, alpha()) + elsif arymethod + retval = alphacheck(value, send(arymethod)) end if retval - return retval.to_s + return retval else raise Puppet::Error, "%s is not a valid %s" % [value, self.class.name] end end - end - # Somewhat uniquely, this state does not actually change anything -- it - # just calls +@parent.sync+, which writes out the whole cron tab for - # the user in question. There is no real way to change individual cron - # jobs without rewriting the entire cron file. - # - # Note that this means that managing many cron jobs for a given user - # could currently result in multiple write sessions for that user. - newstate(:command) do - desc "The command to execute in the cron job. The environment - provided to the command varies by local system rules, and it is - best to always provide a fully qualified command. The user's - profile is not sourced when the command is run, so if the - user's environment is desired it should be sourced manually." - - # Normally this would retrieve the current value, but our state is not - # actually capable of doing so. The Cron class does the actual tab - # retrieval, so all this method does is default to :notfound for @is. - def retrieve - unless defined? @is and ! @is.nil? - @is = :notfound - end - end - # Determine whether the cron job should be destroyed, and figure - # out which event to return. Finally, call @parent.sync to write the - # cron tab. - def sync - event = nil - if @is == :notfound - #@is = @should - event = :cron_created - # We're the first state, so if we're creating the job - # then sync all of the other states - @parent.eachstate { |state| - next if state == self - state.sync(true) - } - - @is = self.should - elsif self.should == :notfound - @parent.remove(true) - event = :cron_deleted - elsif self.insync? - return nil - else - @is = self.should - event = :cron_changed - end - - @parent.store - - return event + def shouldprocess(value) + val = validate(value, *self.class.checking) + return val.to_s end end - newstate(:minute, CronParam) do - self.boundaries = [0, 59] - desc "The minute at which to run the cron job. + class CronMinute < CronParam + @name = :minute + @checking = [0, 59] + @doc = "The minute at which to run the cron job. Optional; if specified, must be between 0 and 59, inclusive." end - newstate(:hour, CronParam) do - self.boundaries = [0, 23] - desc "The hour at which to run the cron job. Optional; + class CronHour < CronParam + @name = :hour + @checking = [0, 23] + @doc = "The hour at which to run the cron job. Optional; if specified, must be between 0 and 23, inclusive." end - newstate(:weekday, CronParam) do - def alpha - %w{sunday monday tuesday wednesday thursday friday saturday} - end - self.boundaries = [0, 6] - desc "The weekday on which to run the command. + class CronWeekday < CronParam + @name = :weekday + @checking = [0, 6, :weekdays] + @doc = "The weekday on which to run the command. Optional; if specified, must be between 0 and 6, inclusive, with 0 being Sunday, or must be the name of the day (e.g., Tuesday)." end - newstate(:month, CronParam) do - def alpha - %w{january february march april may june july - august september october november december} - end - self.boundaries = [1, 12] - desc "The month of the year. Optional; if specified + class CronMonth < CronParam + @name = :month + @checking = [1, 12, :months] + @doc = "The month of the year. Optional; if specified must be between 1 and 12 or the month name (e.g., December)." end - newstate(:monthday, CronParam) do - self.boundaries = [1, 31] - desc "The day of the month on which to run the + class CronMonthDay < CronParam + @name = :monthday + @checking = [1, 31] + @doc = "The day of the month on which to run the command. Optional; if specified, must be between 1 and 31." end + end - newparam(:name) do - desc "The symbolic name of the cron job. This name + class Type + # Model the actual cron jobs. Supports all of the normal cron job fields + # as parameters, with the 'command' as the single state. Also requires a + # completely symbolic 'name' paremeter, which gets written to the file + # and is used to manage the job. + class Cron < Type + @states = [ + Puppet::State::CronCommand, + Puppet::State::CronMinute, + Puppet::State::CronHour, + Puppet::State::CronWeekday, + Puppet::State::CronMonth, + Puppet::State::CronMonthDay + ] + @parameters = [ + :user, + :name + ] + + @paramdoc[:name] = "The symbolic name of the cron job. This name is used for human reference only." - end - - newparam(:user) do - desc "The user to run the command as. This user must + @paramdoc[:user] = "The user to run the command as. This user must be allowed to run cron jobs, which is not currently checked by Puppet." - end - - @doc = "Installs and manages cron jobs. All fields except the command - and the user are optional, although specifying no periodic - fields would result in the command being executed every - minute. While the name of the cron job is not part of the actual - job, it is used by Puppet to store and retrieve it. If you specify - a cron job that matches an existing job in every way except name, - then the jobs will be considered equivalent and the new name will - be permanently associated with that job. Once this association is - made and synced to disk, you can then manage the job normally." - @name = :cron - @namevar = :name - - @loaded = {} - - @synced = {} - - @instances = {} - - case Facter["operatingsystem"].value - when "SunOS": - @crontype = Puppet::CronType::SunOS - else - @crontype = Puppet::CronType::Default - end - class << self - attr_accessor :crontype - end + @doc = "Installs and manages cron jobs. All fields except the command + and the user are optional, although specifying no periodic + fields would result in the command being executed every + minute. While the name of the cron job is not part of the actual + job, it is used by Puppet to store and retrieve it. If you specify + a cron job that matches an existing job in every way except name, + then the jobs will be considered equivalent and the new name will + be permanently associated with that job. Once this association is + made and synced to disk, you can then manage the job normally." + @name = :cron + @namevar = :name - attr_accessor :uid + @loaded = {} - # Override the Puppet::Type#[]= method so that we can store the instances - # in per-user arrays. Then just call +super+. - def self.[]=(name, object) - self.instance(object) - super - end + @synced = {} - # In addition to removing the instances in @objects, Cron has to remove - # per-user cron tab information. - def self.clear @instances = {} - @loaded = {} - @synced = {} - super - end - # Override the default Puppet::Type method, because instances - # also need to be deleted from the @instances hash - def self.delete(child) - if @instances.include?(child[:user]) - if @instances[child[:user]].include?(child) - @instances[child[:user]].delete(child) + case Facter["operatingsystem"].value + when "SunOS": + @crontype = Puppet::CronType::SunOS + else + @crontype = Puppet::CronType::Default + end + + class << self + attr_accessor :crontype + end + + attr_accessor :uid + + # Override the Puppet::Type#[]= method so that we can store the instances + # in per-user arrays. Then just call +super+. + def self.[]=(name, object) + self.instance(object) + super + end + + # In addition to removing the instances in @objects, Cron has to remove + # per-user cron tab information. + def self.clear + @instances = {} + @loaded = {} + @synced = {} + super + end + + # Override the default Puppet::Type method, because instances + # also need to be deleted from the @instances hash + def self.delete(child) + if @instances.include?(child[:user]) + if @instances[child[:user]].include?(child) + @instances[child[:user]].delete(child) + end end + super end - super - end - # Return the fields found in the cron tab. - def self.fields - return [:minute, :hour, :monthday, :month, :weekday, :command] - end + # Return the fields found in the cron tab. + def self.fields + return [:minute, :hour, :monthday, :month, :weekday, :command] + end - # Return the header placed at the top of each generated file, warning - # users that modifying this file manually is probably a bad idea. - def self.header + # Return the header placed at the top of each generated file, warning + # users that modifying this file manually is probably a bad idea. + def self.header %{#This file was autogenerated at #{Time.now} by puppet. While it # can still be managed manually, it is definitely not recommended. # Note particularly that the comments starting with 'Puppet Name' should # not be deleted, as doing so could cause duplicate cron jobs.\n} - end + end - # Store a new instance of a cron job. Called from Cron#initialize. - def self.instance(obj) - user = obj[:user] - if @instances.include?(user) - unless @instances[obj[:user]].include?(obj) - @instances[obj[:user]] << obj + # Store a new instance of a cron job. Called from Cron#initialize. + def self.instance(obj) + user = obj[:user] + if @instances.include?(user) + unless @instances[obj[:user]].include?(obj) + @instances[obj[:user]] << obj + end + else + @instances[obj[:user]] = [obj] end - else - @instances[obj[:user]] = [obj] end - end - # Parse a user's cron job into individual cron objects. - # - # Autogenerates names for any jobs that don't already have one; these - # names will get written back to the file. - # - # This method also stores existing comments, and it stores all cron - # jobs in order, mostly so that comments are retained in the order - # they were written and in proximity to the same jobs. - def self.parse(user, text) - count = 0 - hash = {} - name = nil - unless @instances.include?(user) - @instances[user] = [] - end - text.chomp.split("\n").each { |line| - case line - when /^# Puppet Name: (\w+)$/: name = $1 - when /^#/: - # add other comments to the list as they are - @instances[user] << line - else - if match = /^(\S+) (\S+) (\S+) (\S+) (\S+) (.+)$/.match(line) - fields().zip(match.captures).each { |param, value| - unless value == "*" - unless param == :command - if value =~ /,/ - value = value.split(",") + # Parse a user's cron job into individual cron objects. + # + # Autogenerates names for any jobs that don't already have one; these + # names will get written back to the file. + # + # This method also stores existing comments, and it stores all cron + # jobs in order, mostly so that comments are retained in the order + # they were written and in proximity to the same jobs. + def self.parse(user, text) + count = 0 + hash = {} + name = nil + unless @instances.include?(user) + @instances[user] = [] + end + text.chomp.split("\n").each { |line| + case line + when /^# Puppet Name: (\w+)$/: name = $1 + when /^#/: + # add other comments to the list as they are + @instances[user] << line + else + if match = /^(\S+) (\S+) (\S+) (\S+) (\S+) (.+)$/.match(line) + fields().zip(match.captures).each { |param, value| + unless value == "*" + unless param == :command + if value =~ /,/ + value = value.split(",") + end end + hash[param] = value end - hash[param] = value - end - } - else - raise Puppet::Error, "Could not match '%s'" % line - end - - cron = nil - unless name - Puppet.info "Autogenerating name for %s" % hash[:command] - name = "cron-%s" % hash.object_id - end - - unless hash.include?(:command) - raise Puppet::DevError, "No command for %s" % name - end - # if the cron already exists with that name... - if cron = Puppet.type(:cron)[name] - # do nothing... - elsif tmp = @instances[user].reject { |obj| - ! obj.is_a?(self) - }.find { |obj| - obj.should(:command) == hash[:command] } - # if we can find a cron whose spec exactly matches + else + raise Puppet::Error, "Could not match '%s'" % line + end - # we now have a cron job whose command exactly matches - # let's see if the other fields match - txt = tmp.to_cron.sub(/#.+\n/,'') + cron = nil + unless name + Puppet.info "Autogenerating name for %s" % hash[:command] + name = "cron-%s" % hash.object_id + end - if txt == line - cron = tmp + unless hash.include?(:command) + raise Puppet::DevError, "No command for %s" % name end - else - # create a new cron job, since no existing one - # seems to match - cron = self.create( - :name => name - ) + # if the cron already exists with that name... + if cron = Puppet::Type::Cron[name] + # do nothing... + elsif tmp = @instances[user].reject { |obj| + ! obj.is_a?(Cron) + }.find { |obj| + obj.should(:command) == hash[:command] + } + # if we can find a cron whose spec exactly matches + + # we now have a cron job whose command exactly matches + # let's see if the other fields match + txt = tmp.to_cron.sub(/#.+\n/,'') + + if txt == line + cron = tmp + end + else + # create a new cron job, since no existing one + # seems to match + cron = Puppet::Type::Cron.create( + :name => name + ) + end + + hash.each { |param, value| + cron.is = [param, value] + } + hash.clear + name = nil + count += 1 end + } + end - hash.each { |param, value| - cron.is = [param, value] - } - hash.clear - name = nil - count += 1 + # Retrieve a given user's cron job, using the @crontype's +retrieve+ + # method. Returns nil if there was no cron job; else, returns the + # number of cron instances found. + def self.retrieve(user) + text = @crontype.read(user) + if $? != 0 + # there is no cron file + return nil + else + self.parse(user, text) end - } - end - # Retrieve a given user's cron job, using the @crontype's +retrieve+ - # method. Returns nil if there was no cron job; else, returns the - # number of cron instances found. - def self.retrieve(user) - text = @crontype.read(user) - if $? != 0 - # there is no cron file - return nil - else - self.parse(user, text) + @loaded[user] = Time.now end - @loaded[user] = Time.now - end - - # Store the user's cron tab. Collects the text of the new tab and - # sends it to the +@crontype+ module's +write+ function. Also adds - # header warning users not to modify the file directly. - def self.store(user) - if @instances.include?(user) - @crontype.write(user, self.header + self.tab(user)) - @synced[user] = Time.now - else - Puppet.notice "No cron instances for %s" % user + # Store the user's cron tab. Collects the text of the new tab and + # sends it to the +@crontype+ module's +write+ function. Also adds + # header warning users not to modify the file directly. + def self.store(user) + if @instances.include?(user) + @crontype.write(user, self.header + self.tab(user)) + @synced[user] = Time.now + else + Puppet.notice "No cron instances for %s" % user + end end - end - # Collect all Cron instances for a given user and convert them - # into literal text. - def self.tab(user) - if @instances.include?(user) - return @instances[user].collect { |obj| - if obj.is_a? self - obj.to_cron - else - obj.to_s - end - }.join("\n") + "\n" - else - Puppet.notice "No cron instances for %s" % user + # Collect all Cron instances for a given user and convert them + # into literal text. + def self.tab(user) + if @instances.include?(user) + return @instances[user].collect { |obj| + if obj.is_a?(Cron) + obj.to_cron + else + obj.to_s + end + }.join("\n") + "\n" + else + Puppet.notice "No cron instances for %s" % user + end end - end - # Return the last time a given user's cron tab was loaded. Could - # be used for reducing writes, but currently is not. - def self.loaded?(user) - if @loaded.include?(user) - return @loaded[user] - else - return nil + # Return the last time a given user's cron tab was loaded. Could + # be used for reducing writes, but currently is not. + def self.loaded?(user) + if @loaded.include?(user) + return @loaded[user] + else + return nil + end end - end - def paramuser=(user) - require 'etc' + def paramuser=(user) + require 'etc' - begin - obj = Etc.getpwnam(user) - @uid = obj.uid - rescue ArgumentError - raise Puppet::Error, "User %s not found" % user + begin + obj = Etc.getpwnam(user) + @uid = obj.uid + rescue ArgumentError + raise Puppet::Error, "User %s not found" % user + end + @parameters[:user] = user end - @parameters[:user] = user - end - # Override the default Puppet::Type method because we need to call - # the +@crontype+ retrieve method. - def retrieve - unless @parameters.include?(:user) - raise Puppet::Error, "You must specify the cron user" - end + # Override the default Puppet::Type method because we need to call + # the +@crontype+ retrieve method. + def retrieve + unless @parameters.include?(:user) + raise Puppet::Error, "You must specify the cron user" + end - self.class.retrieve(@parameters[:user]) - self.eachstate { |st| st.retrieve } - end + self.class.retrieve(@parameters[:user]) + self.eachstate { |st| st.retrieve } + end - # Write the entire user's cron tab out. - def store - self.class.store(self[:user]) - end + # Write the entire user's cron tab out. + def store + self.class.store(@parameters[:user]) + end - # Convert the current object a cron-style string. Adds the cron name - # as a comment above the cron job, in the form '# Puppet Name: <name>'. - def to_cron - hash = {:command => @states[:command].should || @states[:command].is } + # Convert the current object a cron-style string. Adds the cron name + # as a comment above the cron job, in the form '# Puppet Name: <name>'. + def to_cron + hash = {:command => @states[:command].should || @states[:command].is } - # Collect all of the values that we have - self.class.fields().reject { |f| f == :command }.each { |param| - if @states.include?(param) - hash[param] = @states[param].should_to_s - end - } + # Collect all of the values that we have + self.class.fields().reject { |f| f == :command }.each { |param| + if @states.include?(param) + hash[param] = @states[param].should_to_s + end + } - return "# Puppet Name: %s\n" % self.name + - self.class.fields.collect { |f| - hash[f] || "*" - }.join(" ") + return "# Puppet Name: %s\n" % self.name + + self.class.fields.collect { |f| + hash[f] || "*" + }.join(" ") + end end end end diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index 4d4e1d624..1c45b7b7f 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -1,33 +1,18 @@ -module Puppet - newtype(:exec) do - @doc = "Executes external commands. It is critical that all commands - executed using this mechanism can be run multiple times without - harm, i.e., they are *idempotent*. One useful way to create idempotent - commands is to use the *creates* parameter. - - It is worth nothing that ``exec`` is special, in that it is not - currently considered an error to have multiple ``exec`` instances - with the same name. This was done purely because it had to be this - way in order to get certain functionality, but it complicates things. - In particular, you will not be able to use ``exec`` instances that - share their commands with other instances as a dependency, since - Puppet has no way of knowing which instance you mean. - - It is recommended to avoid duplicate names whenever possible." - - require 'open3' - require 'puppet/type/state' - - newstate(:returns) do |state| - munge do |value| - value.to_s - end - defaultto "0" +require 'open3' +require 'puppet/type/state' +module Puppet + # okay, how do we deal with parameters that don't have operations + # associated with them? + class State + # this always runs + class Returns < Puppet::State attr_reader :output - desc "The expected return code. An error will be returned if the + + @doc = "The expected return code. An error will be returned if the executed command returns something else." + @name = :returns # Make output a bit prettier def change_to_s @@ -105,6 +90,14 @@ module Puppet # handlers correctly Puppet::Util.asuser(@parent[:user], @parent[:group]) { # capture both stdout and stderr + + #stdin, stdout, stderr = Open3.popen3(self.parent[:command]) + #@output = stdout.read + #err = stderr.read + + #stderr = Puppet::Util.capture_stderr { + # @output = %x{#{self.parent[:command]}} + #} if @parent[:user] unless defined? @@alreadywarned Puppet.warning( @@ -116,6 +109,12 @@ module Puppet else @output = %x{#{self.parent[:command]} 2>&1} end + + #if err != "" + # stderr.split(/\n/).each { |line| + # self.send(:err, line) + # } + #end } status = $? @@ -143,52 +142,122 @@ module Puppet return :executed_command end end + end - newparam(:command) do - isnamevar - desc "The actual command to execute." - end - - newparam(:path) do - desc "The search path used for command execution. + class Type + class Exec < Type + # this is kind of hackish, using the return value as the + # state, but apparently namevars can't also be states + # who knew? + @states = [ + Puppet::State::Returns + ] + + @parameters = [ + :path, + :user, + :group, + :creates, + :cwd, + :refreshonly, + :command + ] + + @paramdoc[:path] = "The search path used for command execution. Commands must be fully qualified if no path is specified." - end + @paramdoc[:user] = "The user to run the command as. Note that if you use + this then any error output is not currently captured. This is mostly + because of a bug within Ruby." + @paramdoc[:group] = "The group to run the command as." + @paramdoc[:cwd] = "The directory from which to run the command. If + this directory does not exist, the command will fail." + @paramdoc[:refreshonly] = "The command should only be run as a + refresh mechanism for when a dependent object is changed." + @paramdoc[:command] = "The actual command to execute." + @paramdoc[:creates] = "A file that this command creates. If this + parameter is provided, then the command will only be run + if the specified file does not exist." + + @doc = "Executes external commands. It is critical that all commands + executed using this mechanism can be run multiple times without + harm, i.e., they are *idempotent*. One useful way to create idempotent + commands is to use the *creates* parameter. + + It is worth nothing that ``exec`` is special, in that it is not + currently considered an error to have multiple ``exec`` instances + with the same name. This was done purely because it had to be this + way in order to get certain functionality, but it complicates things. + In particular, you will not be able to use ``exec`` instances that + share their commands with other instances as a dependency, since + Puppet has no way of knowing which instance you mean. + + It is recommended to avoid duplicate names whenever possible." + @name = :exec + @namevar = :command + + # Exec names are not isomorphic with the objects. + @isomorphic = false + + def initialize(hash) + # default to erroring on a non-zero return + if hash.include?("returns") + if hash["returns"].is_a?(Fixnum) + hash["returns"] = hash["returns"].to_s + end + elsif hash.include?(:returns) + if hash[:returns].is_a?(Fixnum) + hash[:returns] = hash[:returns].to_s + end + else + hash[:returns] = "0" + end - newparam(:user) do - desc "The user to run the command as. Note that if you - use this then any error output is not currently captured. This - is mostly because of a bug within Ruby." + super - munge do |user| - unless Process.uid == 0 - raise Puppet::Error, - "Only root can execute commands as other users" + if self[:command].nil? + raise TypeError.new("Somehow the command is nil") end - require 'etc' - method = :getpwnam - case user - when Integer - method = :getpwuid - when /^\d+$/ - user = user.to_i - method = :getpwuid + # if we're not fully qualified, require a path + if self[:command] !~ /^\// + if self[:path].nil? + raise TypeError, + "both unqualifed and specified no search path" + end end - begin - Etc.send(method, user) - rescue ArgumentError - raise Puppet::Error, "No such user %s" % user + end + + def output + if self.state(:returns).nil? + return nil + else + return self.state(:returns).output end + end - return user + # FIXME if they try to set this and fail, then we should probably + # fail the entire exec, right? + def paramcreates=(file) + unless file =~ %r{^#{File::SEPARATOR}} + raise Puppet::Error, "'creates' files must be fully qualified." + end + @parameters[:creates] = file end - end - newparam(:group) do - desc "The group to run the command as." + def paramcwd=(dir) + if dir.is_a?(Array) + dir = dir[0] + end + + unless File.directory?(dir) + raise Puppet::Error, "Directory '%s' does not exist" % dir + end + + @parameters[:cwd] = dir + end # Execute the command as the specified group - munge do |group| + def paramgroup=(group) require 'etc' method = :getgrnam case group @@ -204,74 +273,42 @@ module Puppet raise Puppet::Error, "No such group %s" % group end - group + @parameters[:group] = group end - end - newparam(:cwd) do - desc "The directory from which to run the command. If - this directory does not exist, the command will fail." - - munge do |dir| - if dir.is_a?(Array) - dir = dir[0] + # Execute the command as the specified user + def paramuser=(user) + unless Process.uid == 0 + raise Puppet::Error, + "Only root can execute commands as other users" end + require 'etc' - unless File.directory?(dir) - raise Puppet::Error, "Directory '%s' does not exist" % dir + method = :getpwnam + case user + when Integer + method = :getpwuid + when /^\d+$/ + user = user.to_i + method = :getpwuid end - - dir - end - end - - newparam(:refreshonly) do - desc "The command should only be run as a - refresh mechanism for when a dependent object is changed." - end - - newparam(:creates) do - desc "A file that this command creates. If this - parameter is provided, then the command will only be run - if the specified file does not exist." - - # FIXME if they try to set this and fail, then we should probably - # fail the entire exec, right? - validate do |file| - unless file =~ %r{^#{File::SEPARATOR}} - raise Puppet::Error, "'creates' files must be fully qualified." + begin + Etc.send(method, user) + rescue ArgumentError + raise Puppet::Error, "No such user %s" % user end - end - end - - # Exec names are not isomorphic with the objects. - @isomorphic = false - validate do - # if we're not fully qualified, require a path - if self[:command] !~ /^\// - if self[:path].nil? - raise TypeError, - "both unqualifed and specified no search path" - end + @parameters[:user] = user end - end - def output - if self.state(:returns).nil? - return nil - else - return self.state(:returns).output + # this might be a very, very bad idea... + def refresh + self.state(:returns).sync end - end - # this might be a very, very bad idea... - def refresh - self.state(:returns).sync - end - - def to_s - "exec(%s)" % self.name + def to_s + "exec(%s)" % self.name + end end end end diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index 8a2301838..0f057b869 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -12,24 +12,18 @@ require 'puppet/type/state' require 'puppet/type/nameservice' module Puppet - newtype(:group, Puppet::Type::NSSType) do - @doc = "Manage groups. This type can only create groups. Group - membership must be managed on individual users." - - case Facter["operatingsystem"].value - when "Darwin": - @parentstate = Puppet::NameService::NetInfo::NetInfoState - @parentmodule = Puppet::NameService::NetInfo - else - @parentstate = Puppet::NameService::ObjectAdd::ObjectAddGroup - @parentmodule = Puppet::NameService::ObjectAdd - end - - newstate(:gid, @parentstate) do - desc "The group ID. Must be specified numerically. If not + class State + module GroupGID + def self.doc + "The group ID. Must be specified numerically. If not specified, a number will be picked, which can result in ID differences across systems and thus is not recommended. The GID is picked according to local system standards." + end + + def self.name + :gid + end def autogen highest = 0 @@ -44,7 +38,7 @@ module Puppet return highest + 1 end - munge do |gid| + def shouldprocess(gid) case gid when String if gid =~ /^[-0-9]+$/ @@ -68,57 +62,88 @@ module Puppet return gid end end + end - class << self - attr_accessor :netinfodir - end + class Type + class Group < Type + statenames = [ + "GroupGID" + ] + case Facter["operatingsystem"].value + when "Darwin": + @statemodule = Puppet::NameService::NetInfo + else + @statemodule = Puppet::NameService::ObjectAdd + end - @netinfodir = "groups" + @states = statenames.collect { |name| + fullname = @statemodule.to_s + "::" + name + begin + eval(fullname) + rescue NameError + raise Puppet::DevError, "Could not retrieve state class %s" % + fullname + end + }.each { |klass| + klass.complete + } + + @name = :group + @namevar = :name + + @parameters = [:name] - newparam(:name) do - desc "The group name. While naming limitations vary by + class << self + attr_accessor :netinfodir + attr_accessor :statemodule + end + + @netinfodir = "groups" + + @paramdoc[:name] = "The group name. While naming limitations vary by system, it is advisable to keep the name to the degenerate limitations, which is a maximum of 8 characters beginning with a letter." - isnamevar - end + @doc = "Manage groups. This type can only create groups. Group + membership must be managed on individual users." - def exists? - self.class.parentmodule.exists?(self) - end - - def getinfo(refresh = false) - if @groupinfo.nil? or refresh == true - begin - @groupinfo = Etc.getgrnam(self.name) - rescue ArgumentError => detail - @groupinfo = nil - end + def exists? + self.class.statemodule.exists?(self) end - @groupinfo - end + def getinfo(refresh = false) + if @groupinfo.nil? or refresh == true + begin + @groupinfo = Etc.getgrnam(self.name) + rescue ArgumentError => detail + @groupinfo = nil + end + end - def initialize(hash) - @groupinfo = nil - super - end + @groupinfo + end - def retrieve - if self.exists? + def initialize(hash) + @groupinfo = nil super - else - # the group does not exist - unless @states.include?(:gid) - self[:gid] = :auto - end + end - @states.each { |name, state| - state.is = :notfound - } + def retrieve + if self.exists? + super + else + # the group does not exist + unless @states.include?(:gid) + self[:gid] = :auto + end - return + @states.each { |name, state| + state.is = :notfound + } + + return + end end end end diff --git a/lib/puppet/type/nameservice.rb b/lib/puppet/type/nameservice.rb index 4fccaeb17..2e289936a 100755 --- a/lib/puppet/type/nameservice.rb +++ b/lib/puppet/type/nameservice.rb @@ -1,225 +1,3 @@ -require 'puppet/type' - -module Puppet -class Type - class NSSType < Puppet::Type - class << self - attr_reader :parentstate, :parentmodule - - def newstate(*args, &block) - s = super(*args, &block) - - if s.respond_to?(:finish) - s.finish - end - end - end - end -end - -class State - # This is the state that all other Nameservice states descend from. It sets - # the standard for how one interacts with these state objects, but it leaves - # out any implementation details. See the 'posix' stuff for the basics - # on how to retrieve information on most systems, but any adding of information - # is done specially per-system (e.g., netinfo, useradd, adduser). - class NSSState < Puppet::State - class << self - # Are all changes to states done in one step or do all states need - # to be synced individually? This differentiates between netinfo, - # in which creation cannot be used to fill out information, and - # things like useradd, in which creation can be done with all - # information in one swell foop. - def allatonce? - Puppet.info "Returning allatonce %s" % @allatonce - if defined? @allatonce - return @allatonce - else - return false - end - end - - # Yes, this value will autogenerate. - def isautogen - @isautogen = true - end - - # Can we autogenerate a value for this field? If a required field - # can be autogenerated then we don't require a value. - def autogen? - if self.method_defined?(:autogen) or - (defined? @isautogen and @isautogen) - return true - else - return false - end - end - - # Yes, this field is optional - def isoptional - @isoptional = true - end - - # Is this field optional? Defaults to false. - def isoptional? - if defined? @isoptional - return @isoptional - else - return false - end - end - - # What method is used to retrieve the value from the POSIX struct? - # Really, these method names should be stored in this class somewhere, - # in a map or something, but then I would have to differentiate - # between the different posix classes (e.g., user and group). In the - # end, we're _only_ using classes that _do_ have posix structs, - # so we might as well store the method in the class definition, - # rather than forcing it to be abstracted out or whatever. - def posixmethod - if defined? @posixmethod - return @posixmethod - else - return self.name - end - end - end - - # We use the POSIX interfaces to retrieve all information, so we don't - # have to worry about abstracting that across the system. Any class - # can still override this, but it should work for the vast majority of - # cases. - def retrieve - if obj = @parent.getinfo(true) - - if method = self.class.posixmethod || self.class.name - @is = obj.send(method) - else - raise Puppet::DevError, - "%s has no posixmethod" % self.class - end - else - @is = :notfound - end - end - - # Sync the information. - def sync - event = nil - # they're in sync some other way - if self.insync? - return nil - end - if @is == :notfound - self.retrieve - 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 self.should == :notfound - Puppet.info "creating" - event = syncname() - - Puppet.info "created with event %s" % event - - return event - # if the whole object is created at once, just return - # an event saying so - #if self.class.allatonce? - # return event - #end - end - - unless @parent.exists? - raise Puppet::DevError, - "%s %s does not exist; cannot set %s" % - [@parent.class.name, @parent.name, self.class.name] - end - - # this needs to be set either by the individual state - # or its parent class - cmd = self.modifycmd - - self.debug "Executing %s" % cmd.inspect - - output = %x{#{cmd} 2>&1} - - - unless $? == 0 - raise Puppet::Error, "Could not modify %s on %s %s: %s" % - [self.class.name, @parent.class.name, - @parent.name, output] - end - - if event - return event - else - return "#{@parent.class.name}_modified".intern - end - end - - private - # This is only used when creating or destroying the object. - def syncname - Puppet.info "Creating %s" % self.name - cmd = nil - event = nil - if self.should == :notfound - # we need to remove the object... - unless @parent.exists? - # the group already doesn't exist - return nil - end - - # again, needs to be set by the ind. state or its - # parent - cmd = self.deletecmd - type = "delete" - else - if @parent.exists? - return nil - end - - # blah blah, define elsewhere, blah blah - cmd = self.addcmd - type = "create" - end - self.debug "Executing %s" % cmd.inspect - - output = %x{#{cmd} 2>&1} - - unless $? == 0 - raise Puppet::Error, "Could not %s %s %s: %s" % - [type, @parent.class.name, @parent.name, output] - end - - # we want object creation to show up as one event, - # not many - unless self.class.allatonce? - Puppet.debug "%s is not allatonce" % self.class.name - if type == "create" - @parent.eachstate { |state| - state.sync - state.retrieve - } - end - end - - return "#{@parent.class.name}_#{type}d".intern - end - end -end -end - -# Here's where we decide what type of objects we'll be dealing with. -case Facter["operatingsystem"].value -when "Darwin": - require 'puppet/type/nameservice/netinfo' -else - require 'puppet/type/nameservice/objectadd' -end - - -# $Id$ +require 'puppet/type/nameservice/posix' +require 'puppet/type/nameservice/netinfo' +require 'puppet/type/nameservice/objectadd' diff --git a/lib/puppet/type/nameservice/netinfo.rb b/lib/puppet/type/nameservice/netinfo.rb index f8334c774..e3e2bdece 100644 --- a/lib/puppet/type/nameservice/netinfo.rb +++ b/lib/puppet/type/nameservice/netinfo.rb @@ -5,6 +5,11 @@ require 'puppet' require 'puppet/type/nameservice/posix' module Puppet + class Type + # Return the NetInfo directory in which a given object type is stored. + # Defaults to the type's name if @netinfodir is unset. + end + module NameService module NetInfo # Verify that we've got all of the commands we need. @@ -51,22 +56,16 @@ module Puppet end end - # The state responsible for handling netinfo objects. Because they - # are all accessed using the exact same interface, we can just - # abstract the differents using a simple map where necessary - # (the netinfokeymap). - class NetInfoState < Puppet::State::NSSState - @netinfokeymap = { - :comment => "realname" - } - - @@allatonce = false + class NetInfoState < POSIX::POSIXState + # Should we do all of the changes at once? + def self.allatonce? + false + end - # Similar to posixmethod, what key do we use to get data? Defaults - # to being the object name. + # Similar to posixmethod, what key do we use to get data? def self.netinfokey - if @netinfokeymap.include?(self.name) - return @netinfokeymap[self.name] + if defined? @netinfokey and @netinfokey + return @netinfokey else return self.name end @@ -148,6 +147,34 @@ module Puppet cmd.join(" ") end end + + class GroupGID < NetInfoState + end + + class UserUID < NetInfoState + end + + class UserGID < NetInfoState + end + + class UserComment < NetInfoState + @netinfokey = "realname" + end + + class UserHome < NetInfoState + end + + class UserShell < NetInfoState + end + + class UserLocked < NetInfoState + end + + class UserExpire < NetInfoState + end + + class UserInactive < NetInfoState + end end end end diff --git a/lib/puppet/type/nameservice/objectadd.rb b/lib/puppet/type/nameservice/objectadd.rb index df2a94902..cc25c5f5f 100644 --- a/lib/puppet/type/nameservice/objectadd.rb +++ b/lib/puppet/type/nameservice/objectadd.rb @@ -1,6 +1,17 @@ require 'puppet' module Puppet + class State + # The flag to use to add an object + def self.objectaddflag + if defined? @objectaddflag and @objectaddflag + return @objectaddflag + else + return @name + end + end + end + module NameService module ObjectAdd # Verify that we've got the commands necessary to manage flat files. @@ -24,45 +35,16 @@ module Puppet end end - # The base state class for <object>add operations. - class ObjectAddState < Puppet::State::NSSState - class << self - # Determine the flag to pass to our command. - def objectaddflag - unless defined? @objectaddflag - # Else, return the first letter of the name. I have to - # user a range here, else the character will show up - # as a number, rather than as a string, for some reason. - @objectaddflag = "-" + self.name.to_s[0,1] - Puppet.debug "Setting flag on %s to %s" % - [self.name, @objectaddflag] - end - return @objectaddflag - end - - # Set the flag manually. - def setflag(value) - @objectaddflag = value - end - end - end - - # The state class for doing group operations using groupadd or whatever. - # I could probably have abstracted the User and Group classes into - # a single class, but eh, it just didn't seem worth it. - class ObjectAddGroup < ObjectAddState - class << self - # This is hackish, but hey, it works. - def finish - @allatonce = true - end + class ObjectAddGroup < POSIX::POSIXState + def self.allatonce? + true end def addcmd cmd = ["groupadd"] if gid = @parent.should(:gid) unless gid == :auto - cmd << self.class.objectaddflag << gid + cmd << "-g" << gid end end cmd << @parent.name @@ -84,17 +66,16 @@ module Puppet end end - # The class for adding users using 'adduser'. - class ObjectAddUser < ObjectAddState - class << self - # This is hackish, but hey, it works. - def finish - @allatonce = true - case self.name - when :home: setflag "-d" - end - end + class GroupGID < ObjectAddGroup + @objectaddflag = "-g" + @autogen = true + end + + class ObjectAddUser < POSIX::POSIXState + def self.allatonce? + true end + def addcmd cmd = ["useradd"] @parent.eachstate { |state| @@ -118,14 +99,50 @@ module Puppet end def modifycmd - cmd = [ - "usermod", - self.class.objectaddflag, - "'%s'" % self.should, - @parent.name - ].join(" ") + cmd = [ + "usermod", + self.class.objectaddflag, + "'%s'" % self.should, + @parent.name + ].join(" ") end end + class UserUID < ObjectAddUser + @objectaddflag = "-u" + @autogen = true + end + + class UserGID < ObjectAddUser + @objectaddflag = "-g" + @autogen = true + end + + class UserComment < ObjectAddUser + @objectaddflag = "-c" + end + + class UserHome < ObjectAddUser + @objectaddflag = "-d" + @autogen = true + end + + class UserShell < ObjectAddUser + @objectaddflag = "-s" + @autogen = true + end + + class UserLocked < ObjectAddUser + end + + class UserExpire < ObjectAddUser + @objectaddflag = "-e" + @autogen = true + end + + class UserInactive < ObjectAddUser + @objectaddflag = "-f" + @autogen = true + end end end end diff --git a/lib/puppet/type/nameservice/posix.rb b/lib/puppet/type/nameservice/posix.rb index cf8c371ef..41b069f9d 100644 --- a/lib/puppet/type/nameservice/posix.rb +++ b/lib/puppet/type/nameservice/posix.rb @@ -1,12 +1,210 @@ require 'puppet' -require 'puppet/type/nameservice' module Puppet - class State - # The lowest-level state class for managing NSS/POSIX information. It - # at least knows how to retrieve information, but it does not know how - # to sync anything. - class POSIXState < NSSState + class Type # :nodoc: + # The method that returns what we want from the POSIX struct + def self.posixmethod + if defined? @posixmethod and @posixmethod + return @posixmethod + else + return @name + end + end + end + + module NameService + # This is the base module for basically all of the NSS stuff. It + # should be able to retrieve the info for almost any system, but + # it can't create any information on its own. You need to define + # a subclass of these classes to actually modify the system. + module POSIX + class POSIXState < Puppet::State + class << self + attr_accessor :extender + + # Can we autogenerate a value for this field? If a required field + # can be autogenerated then we don't require a value. + def autogen? + if defined? @autogen + return @autogen + else + return false + end + end + + # Is this field optional? + def optional? + if defined? @optional + return @optional + else + return false + end + end + end + + # The documentation for our module comes from the extending class, + # not directly from the object + def self.doc + if defined? @extender + @extender.doc + else + nil + end + end + + # Find the module to use to extend the current class + def self.complete + mod = "Puppet::State::%s" % + self.to_s.sub(/.+::/,'') + begin + modklass = eval(mod) + rescue NameError + raise Puppet::Error, + "Could not find extender module %s for %s" % + [mod, self.to_s] + end + include modklass + + self.extender = modklass + end + + # Return the method that we'll call on the POSIX struct. + def self.posixmethod + if defined? @extender + if @extender.respond_to?(:posixmethod) + return @extender.posixmethod + else + return @extender.name + end + else + raise Puppet::DevError, + "%s could not retrieve posixmethod" % self + end + end + + def self.name + @extender.name + end + + # we use the POSIX interfaces to retrieve all information, + # so we don't have to worry about abstracting that across + # the system + def retrieve + if obj = @parent.getinfo(true) + + if method = self.class.posixmethod || self.class.name + @is = obj.send(method) + else + raise Puppet::DevError, + "%s has no posixmethod" % self.class + end + else + @is = :notfound + end + end + + # Sync the information. + def sync + event = nil + # they're in sync some other way + if self.insync? + return nil + end + if @is == :notfound + self.retrieve + 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 self.should == :notfound + event = syncname() + + return event + # if the whole object is created at once, just return + # an event saying so + #if self.class.allatonce? + # return event + #end + end + + unless @parent.exists? + raise Puppet::DevError, + "%s %s does not exist; cannot set %s" % + [@parent.class.name, @parent.name, self.class.name] + end + + # this needs to be set either by the individual state + # or its parent class + cmd = self.modifycmd + + self.debug "Executing %s" % cmd.inspect + + output = %x{#{cmd} 2>&1} + + + unless $? == 0 + raise Puppet::Error, "Could not modify %s on %s %s: %s" % + [self.class.name, @parent.class.name, + @parent.name, output] + end + + if event + return event + else + return "#{@parent.class.name}_modified".intern + end + end + + private + # This is only used when creating or destroying the object. + def syncname + cmd = nil + event = nil + if self.should == :notfound + # we need to remove the object... + unless @parent.exists? + # the group already doesn't exist + return nil + end + + # again, needs to be set by the ind. state or its + # parent + cmd = self.deletecmd + type = "delete" + else + if @parent.exists? + return nil + end + + # blah blah, define elsewhere, blah blah + cmd = self.addcmd + type = "create" + end + self.debug "Executing %s" % cmd.inspect + + output = %x{#{cmd} 2>&1} + + unless $? == 0 + raise Puppet::Error, "Could not %s %s %s: %s" % + [type, @parent.class.name, @parent.name, output] + end + + # we want object creation to show up as one event, + # not many + unless self.class.allatonce? + if type == "create" + @parent.eachstate { |state| + state.sync + state.retrieve + } + end + end + + return "#{@parent.class.name}_#{type}d".intern + end + end end end end diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 24246f908..45032c206 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -12,47 +12,20 @@ require 'puppet/type/package/sun.rb' module Puppet class PackageError < Puppet::Error; end - newtype(:package) do - @doc = "Manage packages. Eventually will support retrieving packages - from remote sources but currently only supports packaging - systems which can retrieve their own packages, like ``apt``." - - newstate(:install) do - desc "What state the package should be in. Specifying *true* will - only result in a change if the package is not installed at all; - use *latest* to keep the package (and, depending on the package - system, its prerequisites) up to date. Specifying *false* will - uninstall the package if it is installed. - *true*/*false*/*latest*/``version``" - - munge do |value| - # possible values are: true, false, and a version number - case value - when "latest": - unless @parent.respond_to?(:latest) - self.err @parent.inspect - raise Puppet::Error, - "Package type %s does not support querying versions" % - @parent[:type] - end - return :latest - when true, :installed: - return :installed - when false, :notinstalled: - return :notinstalled - else - # We allow them to set a should value however they want, - # but only specific package types will be able to use this - # value - return value - end - end + class State + class PackageInstalled < Puppet::State + @name = :install + + @doc = "What state the package should be in. Specifying *true* will + only result in a change if the package is not installed at all; use + *latest* to keep the package (and, depending on the package system, its + prerequisites) up to date. Specifying *false* will uninstall the + package if it is installed. *true*/*false*/*latest*/``version``" # Override the parent method, because we've got all kinds of # funky definitions of 'in sync'. def insync? - # Iterate across all of the should values, and see how they - # turn out. + # Iterate across all of the should values, and see how they turn out. @should.each { |should| case should when :installed @@ -85,6 +58,29 @@ module Puppet end end + def shouldprocess(value) + # possible values are: true, false, and a version number + case value + when "latest": + unless @parent.respond_to?(:latest) + self.err @parent.inspect + raise Puppet::Error, + "Package type %s does not support querying versions" % + @parent[:type] + end + return :latest + when true, :installed: + return :installed + when false, :notinstalled: + return :notinstalled + else + # We allow them to set a should value however they want, + # but only specific package types will be able to use this + # value + return value + end + end + def sync method = nil event = nil @@ -130,249 +126,251 @@ module Puppet return event end end + end + + class Type # packages are complicated because each package format has completely # different commands. We need some way to convert specific packages # into the general package object... - attr_reader :version, :pkgtype - - @pkgtypes = [ - Puppet::PackagingType::APT, - Puppet::PackagingType::DPKG, - Puppet::PackagingType::RPM, - Puppet::PackagingType::Yum, - Puppet::PackagingType::Sun - ] - - pkgstr = @pkgtypes.collect {|t| - "``" + t.name.to_s + "``" - }.join(", ") - - @pkgtypehash = {} - - # Now collect the name of each type and store it thusly - @pkgtypes.each { |type| - if type.respond_to?(:typename) - @pkgtypehash[type.typename] = type - else - name = type.to_s.sub(/.+::/, '').downcase.intern - @pkgtypehash[name] = type - end - } - - newparam(:name) do - desc "The package name." - isnamevar - end - - newparam(:type) do - desc "The package format. Currently supports " + pkgstr - end - newparam(:instance) do - desc "A read-only parameter set by the package." - end - newparam(:status) do - desc "A read-only parameter set by the package." - end - #newparam(:version) do - # desc "A read-only parameter set by the package." - #end - newparam(:category) do - desc "A read-only parameter set by the package." - end - newparam(:platform) do - desc "A read-only parameter set by the package." - end - newparam(:root) do - desc "A read-only parameter set by the package." - end - newparam(:vendor) do - desc "A read-only parameter set by the package." - end - newparam(:description) do - desc "A read-only parameter set by the package." - end - @name = :package - @namevar = :name - @listed = false - - @allowedmethods = [:types] - - @default = nil - @platform = nil - - class << self - attr_reader :listed - end - - def self.clear + class Package < Type + attr_reader :version, :pkgtype + + @pkgtypes = [ + Puppet::PackagingType::APT, + Puppet::PackagingType::DPKG, + Puppet::PackagingType::RPM, + Puppet::PackagingType::Yum, + Puppet::PackagingType::Sun + ] + + @pkgtypehash = {} + + # Now collect the name of each type and store it thusly + @pkgtypes.each { |type| + if type.respond_to?(:typename) + @pkgtypehash[type.typename] = type + else + name = type.to_s.sub(/.+::/, '').downcase.intern + @pkgtypehash[name] = type + end + } + + @states = [ + Puppet::State::PackageInstalled + ] + #:version, + @parameters = [ + :name, + :type, + :instance, + :status, + :category, + :platform, + :root, + :vendor, + :description + ] + + @paramdoc[:name] = "The package name." + @paramdoc[:type] = "The package format. Currently supports " + + @pkgtypes.collect {|t| + "``" + t.name.to_s + "``" + }.join(", ") + "." + @paramdoc[:instance] = "A read-only parameter set by the package." + @paramdoc[:status] = "A read-only parameter set by the package." + #@paramdoc[:version] = "A read-only parameter set by the package." + @paramdoc[:category] = "A read-only parameter set by the package." + @paramdoc[:platform] = "A read-only parameter set by the package." + @paramdoc[:root] = "A read-only parameter set by the package." + @paramdoc[:vendor] = "A read-only parameter set by the package." + @paramdoc[:description] = "A read-only parameter set by the package." + + @doc = "Manage packages. Eventually will support retrieving packages + from remote sources but currently only supports packaging + systems which can retrieve their own packages, like ``apt``." + @name = :package + @namevar = :name @listed = false - super - end - # Cache and return the default package type for our current - # platform. - def self.default - if @default.nil? - self.init - end + @allowedmethods = [:types] - return @default - end + @default = nil + @platform = nil - # Figure out what the default package type is for the platform - # on which we're running. - def self.init - unless @platform = Facter["operatingsystem"].value.downcase - raise Puppet::DevError.new( - "Must know platform for package management" - ) + class << self + attr_reader :listed end - case @platform - when "sunos": @default = :sun - when "linux": - case Facter["distro"].value.downcase - when "gentoo": - Puppet.notice "No support for gentoo yet" - @default = nil - when "debian": @default = :apt - when "fedora": @default = :yum - when "redhat": @default = :rpm - else - Puppet.warning "Using rpm as default type for %s" % - Facter["distro"].value - @default = :rpm - end - else - @default = nil + + def self.clear + @listed = false + super end - end - def self.getpkglist - if @types.nil? + # Cache and return the default package type for our current + # platform. + def self.default if @default.nil? self.init end - @types = [@default] + + return @default end - list = @types.collect { |type| - if typeobj = Puppet::PackagingType[type] - # pull all of the objects - typeobj.list + # Figure out what the default package type is for the platform + # on which we're running. + def self.init + unless @platform = Facter["operatingsystem"].value.downcase + raise Puppet::DevError.new( + "Must know platform for package management" + ) + end + case @platform + when "sunos": @default = :sun + when "linux": + case Facter["distro"].value.downcase + when "gentoo": + Puppet.notice "No support for gentoo yet" + @default = nil + when "debian": @default = :apt + when "fedora": @default = :yum + when "redhat": @default = :rpm + else + Puppet.warning "Using rpm as default type for %s" % + Facter["distro"].value + @default = :rpm + end else - raise "Could not find package type '%s'" % type + @default = nil end - }.flatten - @listed = true - return list - end + end - def self.installedpkg(hash) - # this is from code, so we don't have to do as much checking - name = hash[:name] - hash.delete(:name) - - # if it already exists, modify the existing one - if object = Package[name] - states = {} - object.eachstate { |state| - Puppet.debug "Adding %s" % state.name.inspect - states[state.name] = state - } - hash.each { |var,value| - if states.include?(var) - Puppet.debug "%s is a set state" % var.inspect - states[var].is = value - else - Puppet.debug "%s is not a set state" % var.inspect - if object[var] and object[var] != value - Puppet.warning "Overriding %s => %s on %s with %s" % - [var,object[var],name,value] - end + def self.getpkglist + if @types.nil? + if @default.nil? + self.init + end + @types = [@default] + end - #object.state(var).is = value + list = @types.collect { |type| + if typeobj = Puppet::PackagingType[type] + # pull all of the objects + typeobj.list + else + raise "Could not find package type '%s'" % type + end + }.flatten + @listed = true + return list + end - # swap the values if we're a state + def Package.installedpkg(hash) + # this is from code, so we don't have to do as much checking + name = hash[:name] + hash.delete(:name) + + # if it already exists, modify the existing one + if object = Package[name] + states = {} + object.eachstate { |state| + Puppet.debug "Adding %s" % state.name.inspect + states[state.name] = state + } + hash.each { |var,value| if states.include?(var) - Puppet.debug "Swapping %s because it's a state" % var + Puppet.debug "%s is a set state" % var.inspect states[var].is = value - states[var].should = nil else - Puppet.debug "%s is not a state" % var.inspect - Puppet.debug "States are %s" % states.keys.collect { |st| - st.inspect - }.join(" ") + Puppet.debug "%s is not a set state" % var.inspect + if object[var] and object[var] != value + Puppet.warning "Overriding %s => %s on %s with %s" % + [var,object[var],name,value] + end + + #object.state(var).is = value + + # swap the values if we're a state + if states.include?(var) + Puppet.debug "Swapping %s because it's a state" % var + states[var].is = value + states[var].should = nil + else + Puppet.debug "%s is not a state" % var.inspect + Puppet.debug "States are %s" % states.keys.collect { |st| + st.inspect + }.join(" ") + end end - end - } - return object - else # just create it - obj = self.create(:name => name) - hash.each { |var,value| - obj.addis(var,value) - } - return obj + } + return object + else # just create it + obj = self.create(:name => name) + hash.each { |var,value| + obj.addis(var,value) + } + return obj + end end - end - # Retrieve a package type by name; names are symbols. - def self.pkgtype(pkgtype) - if pkgtype.is_a?(String) - pkgtype = pkgtype.intern + # Retrieve a package type by name; names are symbols. + def self.pkgtype(pkgtype) + if pkgtype.is_a?(String) + pkgtype = pkgtype.intern + end + return @pkgtypehash[pkgtype] end - return @pkgtypehash[pkgtype] - end - # okay, there are two ways that a package could be created... - # either through the language, in which case the hash's values should - # be set in 'should', or through comparing against the system, in which - # case the hash's values should be set in 'is' - def initialize(hash) - type = hash["type"] || hash[:type] || self.class.default - self.type2module(type) + # okay, there are two ways that a package could be created... + # either through the language, in which case the hash's values should + # be set in 'should', or through comparing against the system, in which + # case the hash's values should be set in 'is' + def initialize(hash) + type = hash["type"] || hash[:type] || self.class.default + self.type2module(type) - super + super - self.debug "Extending to package type %s" % [@type] + self.debug "Extending to package type %s" % [@type] - unless @states.include?(:install) - self.debug "Defaulting to installing a package" - self[:install] = true - end + unless @states.include?(:install) + self.debug "Defaulting to installing a package" + self[:install] = true + end - unless @parameters.include?(:type) - self[:type] = self.class.default + unless @parameters.include?(:type) + self[:type] = self.class.default + end end - end - def retrieve - if hash = self.query - hash.each { |param, value| - unless self.class.validattr?(param) - hash.delete(param) - end - } + def retrieve + if hash = self.query + hash.each { |param, value| + unless self.class.validarg?(param) + hash.delete(param) + end + } - hash.each { |param, value| - self.is = [param, value] - } - else - self.class.validstates.each { |name| - self.is = [name, :notinstalled] - } + hash.each { |param, value| + self.is = [param, value] + } + else + self.class.validstates.each { |name| + self.is = [name, :notinstalled] + } + end end - end - # Extend the package with the appropriate package type. - def type2module(typename) - if type = self.class.pkgtype(typename) - @type = type - self.extend(type) - else - raise Puppet::Error, "Invalid package type %s" % typename + # Extend the package with the appropriate package type. + def type2module(typename) + if type = self.class.pkgtype(typename) + @type = type + self.extend(type) + else + raise Puppet::Error, "Invalid package type %s" % typename + end end - end - end # Puppet.type(:package) + end # Puppet::Type::Package + end # this is how we retrieve packages class PackageSource diff --git a/lib/puppet/type/package/dpkg.rb b/lib/puppet/type/package/dpkg.rb index 48a1a497b..1d9b54aaf 100755 --- a/lib/puppet/type/package/dpkg.rb +++ b/lib/puppet/type/package/dpkg.rb @@ -32,7 +32,7 @@ module Puppet fields.zip(match.captures) { |field,value| hash[field] = value } - #packages.push Puppet.type(:package).installedpkg(hash) + #packages.push Puppet::Type::Package.installedpkg(hash) else raise Puppet::DevError, "failed to match dpkg line %s" % line @@ -82,7 +82,7 @@ module Puppet fields.zip(match.captures) { |field,value| hash[field] = value } - packages.push Puppet.type(:package).installedpkg(hash) + packages.push Puppet::Type::Package.installedpkg(hash) else raise Puppet::DevError, "Failed to match dpkg line %s" % line diff --git a/lib/puppet/type/package/rpm.rb b/lib/puppet/type/package/rpm.rb index af340ff40..ed88af507 100755 --- a/lib/puppet/type/package/rpm.rb +++ b/lib/puppet/type/package/rpm.rb @@ -53,7 +53,7 @@ module Puppet fields.zip(match.captures) { |field,value| hash[field] = value } - packages.push Puppet.type(:package).installedpkg(hash) + packages.push Puppet::Type::Package.installedpkg(hash) else raise "failed to match rpm line %s" % line end diff --git a/lib/puppet/type/package/sun.rb b/lib/puppet/type/package/sun.rb index 90e5c579e..65da29a31 100755 --- a/lib/puppet/type/package/sun.rb +++ b/lib/puppet/type/package/sun.rb @@ -79,7 +79,7 @@ module Puppet process.each { |line| case line when /^$/: - packages.push Puppet.type(:package).installedpkg(hash) + packages.push Puppet::Type::Package.installedpkg(hash) hash.clear when /\s*(\w+):\s+(.+)/: name = $1 diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index dfe76b401..3d5a87011 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -6,517 +6,558 @@ require 'fileutils' require 'puppet/type/state' require 'puppet/server/fileserver' -module Puppet - newtype(:file) do - @doc = "Manages local files, including setting ownership and - permissions, and allowing creation of both files and directories." - - newparam(:path) do - desc "The path to the file to manage. Must be fully qualified." - isnamevar - end +# We put all of the states in separate files, because there are so many +# of them. +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' - newparam(:backup) do - desc "Whether files should be backed up before +module Puppet + class Type + class PFile < Type + @doc = "Manages local files, including setting ownership and + permissions, and allowing creation of both files and directories." + + @states = [ + Puppet::State::PFileCreate, + Puppet::State::PFileChecksum, + Puppet::State::PFileSource, + Puppet::State::PFileUID, + Puppet::State::PFileGroup, + Puppet::State::PFileMode, + Puppet::State::PFileType + ] + + @parameters = [ + :path, + :backup, + :linkmaker, + :recurse, + :ignore + ] + + @paramdoc[:path] = "The path to the file to manage. Must be fully + qualified." + + @paramdoc[:backup] = "Whether files should be backed up before being replaced. If a ``filebucket`` is specified, files will be backed up there; else, they will be backed up in the same directory with a ``.puppet-bak`` extension." - defaultto true - - munge do |value| - case value - when false, "false": - false - when true, "true": - ".puppet-bak" - when Array: - case value[0] - when "filebucket": - if bucket = Puppet.type(:filebucket).bucket(value[1]) - bucket - else - raise Puppet::Error, - "Could not retrieve filebucket %s" % - value[1] - end - else - raise Puppet::Error, "Invalid backup object type %s" % - value[0].inspect - end - else - raise Puppet::Error, "Invalid backup type %s" % - value.inspect - end - end - end - - newparam(:linkmaker) do - desc "An internal parameter used by the *symlink* + @paramdoc[:linkmaker] = "An internal parameter used by the *symlink* type to do recursive link creation." - end - newparam(:recurse) do - desc "Whether and how deeply to do recursive + @paramdoc[:recurse] = "Whether and how deeply to do recursive management. **false**/*true*/*inf*/*number*" - end - newparam(:ignore) do - desc "A parameter which omits action on files matching + @paramdoc[:ignore] = "A parameter which omits action on files matching specified patterns during recursion. Uses Ruby's builtin globbing engine, so shell metacharacters are fully supported, e.g. ``[a-z]*``. Matches that would descend into the directory structure are ignored, e.g., ``*/*``." - - validate do |value| - unless value.is_a?(Array) or value.is_a?(String) - raise Puppet::DevError.new("Ignore must be a string or an Array") - end - end - end - @depthfirst = false + #no longer a parameter + # @paramdoc[:source] = "Where to retrieve the contents of the files. + # Currently only supports local copying, but will eventually + # support multiple protocols for copying. Arguments are specified + # using either a full local path or using a URI (currently only + # *file* is supported as a protocol)." + - def argument?(arg) - @arghash.include?(arg) - end + @name = :file + @namevar = :path - def handlebackup(file = nil) - # let the path be specified - file ||= self[:path] - # if they specifically don't want a backup, then just say - # we're good - unless FileTest.exists?(file) - return true - end + @depthfirst = false + + PINPARAMS = [:mode, :type, :owner, :group, :checksum] - unless self[:backup] - return true + + def argument?(arg) + @arghash.include?(arg) end - case File.stat(file).ftype - when "directory": - # we don't need to backup directories - return true - when "file": - backup = self[:backup] - case backup - when Puppet::Client::Dipper: - sum = backup.backup(file) - self.info "Filebucketed %s with sum %s" % - [file, sum] + def handlebackup(file = nil) + # let the path be specified + file ||= self[:path] + # if they specifically don't want a backup, then just say + # we're good + unless FileTest.exists?(file) + return true + end + + unless self[:backup] + return true + end + + case File.stat(file).ftype + when "directory": + # we don't need to backup directories return true - when String: - newfile = file + backup - if FileTest.exists?(newfile) + when "file": + backup = self[:backup] + case backup + when Puppet::Client::Dipper: + sum = backup.backup(file) + self.info "Filebucketed %s with sum %s" % + [file, sum] + return true + when String: + newfile = file + backup + if FileTest.exists?(newfile) + begin + File.unlink(newfile) + rescue => detail + self.err "Could not remove old backup: %s" % + detail + return false + end + end begin - File.unlink(newfile) + FileUtils.cp(file, + file + backup) + return true rescue => detail - self.err "Could not remove old backup: %s" % - detail - return false + # since they said they want a backup, let's error out + # if we couldn't make one + raise Puppet::Error.new("Could not back %s up: %s" % + [file, detail.message]) end - end - begin - FileUtils.cp(file, - file + backup) - return true - rescue => detail - # since they said they want a backup, let's error out - # if we couldn't make one - raise Puppet::Error.new("Could not back %s up: %s" % - [file, detail.message]) + else + self.err "Invalid backup type %s" % backup + return false end else - self.err "Invalid backup type %s" % backup + self.notice "Cannot backup files of type %s" % + File.stat(file).ftype return false end - else - self.notice "Cannot backup files of type %s" % - File.stat(file).ftype - return false end - end - - def handleignore(children) - @parameters[:ignore].value.each { |ignore| - ignored = [] - Dir.glob(File.join(self.name,ignore), File::FNM_DOTMATCH) { |match| - ignored.push(File.basename(match)) - } - children = children - ignored - } - return children - end - - def initialize(hash) - # clean out as many references to any file paths as possible - # this was the source of many, many bugs - @arghash = self.argclean(hash) - @arghash.delete(self.class.namevar) - - if @arghash.include?(:source) - @arghash.delete(:source) + def handleignore(children) + @parameters[:ignore].each { |ignore| + ignored = [] + Dir.glob(File.join(self.name,ignore), File::FNM_DOTMATCH) { |match| + ignored.push(File.basename(match)) + } + children = children - ignored + } + return children end + + def initialize(hash) + # clean out as many references to any file paths as possible + # this was the source of many, many bugs + + @arghash = self.argclean(hash) + @arghash.delete(self.class.namevar) + + if @arghash.include?(:source) + @arghash.delete(:source) + end - @stat = nil + @stat = nil + @parameters = Hash.new(false) - # Used for caching clients - @clients = {} + # default to true + self[:backup] = true - super - end - - def newchild(path, hash = {}) - # make local copy of arguments - args = @arghash.dup + # Used for caching clients + @clients = {} - if path =~ %r{^#{File::SEPARATOR}} - raise Puppet::DevError.new( - "Must pass relative paths to PFile#newchild()" - ) - else - path = File.join(self.name, path) + super end - - args[:path] = path - - unless hash.include?(:recurse) - if args.include?(:recurse) - if args[:recurse].is_a?(Integer) - self.notice "Decrementing recurse on %s" % path - args[:recurse] -= 1 # reduce the level of recursion + + def parambackup=(value) + case value + when false, "false": + @parameters[:backup] = false + when true, "true": + @parameters[:backup] = ".puppet-bak" + when Array: + case value[0] + when "filebucket": + if bucket = Puppet::Type::PFileBucket.bucket(value[1]) + @parameters[:backup] = bucket + else + @parameters[:backup] = ".puppet-bak" + raise Puppet::Error, + "Could not retrieve filebucket %s" % + value[1] + end + else + raise Puppet::Error, "Invalid backup object type %s" % + value[0].inspect end + else + raise Puppet::Error, "Invalid backup type %s" % + value.inspect end - end - - hash.each { |key,value| - args[key] = value - } - - child = nil - klass = nil - if @parameters[:linkmaker] and args.include?(:source) and - ! FileTest.directory?(args[:source]) - klass = Puppet.type(:symlink) - - self.debug "%s is a link" % path - # clean up the args a lot for links - old = args.dup - args = { - :target => old[:source], - :path => path - } - else - klass = self.class + + def paramignore=(value) + + #Make sure the value of ignore is in correct type + unless value.is_a?(Array) or value.is_a?(String) + raise Puppet::DevError.new("Ignore must be a string or an Array") + end + + @parameters[:ignore] = value end - # 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] - unless @children.include?(child) - self.notice "Not managing more explicit file %s" % - path - return nil + def newchild(path, hash = {}) + # make local copy of arguments + args = @arghash.dup + + if path =~ %r{^#{File::SEPARATOR}} + raise Puppet::DevError.new( + "Must pass relative paths to PFile#newchild()" + ) + else + path = File.join(self.name, path) end - args.each { |var,value| - next if var == :path - next if var == :name - # behave idempotently - unless child.should(var) == value - child[var] = value + + args[:path] = path + + unless hash.include?(:recurse) + if args.include?(:recurse) + if args[:recurse].is_a?(Integer) + self.notice "Decrementing recurse on %s" % path + args[:recurse] -= 1 # reduce the level of recursion + end end + + end + + hash.each { |key,value| + args[key] = value } - else # create it anew - #notice "Creating new file with args %s" % args.inspect - args[:parent] = self - begin - child = klass.implicitcreate(args) - - # implicit creation can return nil - if child.nil? + + child = nil + klass = nil + if @parameters[:linkmaker] and args.include?(:source) and + ! FileTest.directory?(args[:source]) + klass = Puppet::Type::Symlink + + self.debug "%s is a link" % path + # clean up the args a lot for links + old = args.dup + args = { + :target => old[:source], + :path => path + } + else + klass = self.class + end + + # 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] + unless @children.include?(child) + self.notice "Not managing more explicit file %s" % + path return nil end - @children << child - rescue Puppet::Error => detail - self.notice( - "Cannot manage: %s" % - [detail.message] - ) - self.debug args.inspect - child = nil - rescue => detail - self.notice( - "Cannot manage: %s" % - [detail] - ) - self.debug args.inspect - child = nil + 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 + args[:parent] = self + begin + child = klass.implicitcreate(args) + + # implicit creation can return nil + if child.nil? + return nil + end + @children << child + rescue Puppet::Error => detail + self.notice( + "Cannot manage: %s" % + [detail.message] + ) + self.debug args.inspect + child = nil + rescue => detail + self.notice( + "Cannot manage: %s" % + [detail] + ) + self.debug args.inspect + child = nil + end end + return child end - return child - end - - # Paths are special for files, because we don't actually want to show - # the parent's full path. - def path - unless defined? @path - if defined? @parent - # We only need to behave specially when our parent is also - # a file - if @parent.is_a?(self.class) - # Remove the parent file name - ppath = @parent.path.sub(/\/?file=.+/, '') - @path = [] - if ppath != "/" and ppath != "" - @path << ppath + + # Paths are special for files, because we don't actually want to show + # the parent's full path. + def path + unless defined? @path + if defined? @parent + # We only need to behave specially when our parent is also + # a file + if @parent.is_a?(self.class) + # Remove the parent file name + ppath = @parent.path.sub(/\/?file=.+/, '') + @path = [] + if ppath != "/" and ppath != "" + @path << ppath + end + @path << self.class.name.to_s + "=" + self.name + else + super end - @path << self.class.name.to_s + "=" + self.name else - super - end - else - # The top-level name is always puppet[top], so we don't - # bother with that. And we don't add the hostname - # here, it gets added in the log server thingy. - if self.name == "puppet[top]" - @path = ["/"] - else - # We assume that if we don't have a parent that we - # should not cache the path - @path = [self.class.name.to_s + "=" + self.name] + # The top-level name is always puppet[top], so we don't + # bother with that. And we don't add the hostname + # here, it gets added in the log server thingy. + if self.name == "puppet[top]" + @path = ["/"] + else + # We assume that if we don't have a parent that we + # should not cache the path + @path = [self.class.name.to_s + "=" + self.name] + end end end + + return @path.join("/") end - return @path.join("/") - 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 - if recurse.is_a?(String) - if recurse =~ /^[0-9]+$/ - recurse = Integer(recurse) - #elsif recurse =~ /^inf/ # infinite recursion - else # anything else is infinite recursion - recurse = true + # 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 + if recurse.is_a?(String) + if recurse =~ /^[0-9]+$/ + recurse = Integer(recurse) + #elsif recurse =~ /^inf/ # infinite recursion + else # anything else is infinite recursion + recurse = true + end end - end - # are we at the end of the recursion? - if recurse == 0 - self.info "finished recursing" - return - end + # are we at the end of the recursion? + if recurse == 0 + self.info "finished recursing" + return + end - if recurse.is_a?(Integer) - recurse -= 1 - end + if recurse.is_a?(Integer) + recurse -= 1 + end - self.localrecurse(recurse) - if @states.include?(:source) - self.sourcerecurse(recurse) + self.localrecurse(recurse) + if @states.include?(:source) + self.sourcerecurse(recurse) + end end - end - def localrecurse(recurse) - unless FileTest.exist?(self.name) and self.stat.directory? - #self.info "%s is not a directory; not recursing" % - # self.name - return - end + def localrecurse(recurse) + unless FileTest.exist?(self.name) and self.stat.directory? + #self.info "%s is not a directory; not recursing" % + # self.name + return + end - unless FileTest.directory? self.name - raise Puppet::Error.new( - "Uh, somehow trying to manage non-dir %s" % self.name - ) - end - unless FileTest.readable? self.name - self.notice "Cannot manage %s: permission denied" % self.name - return - end + unless FileTest.directory? self.name + raise Puppet::Error.new( + "Uh, somehow trying to manage non-dir %s" % self.name + ) + end + unless FileTest.readable? self.name + self.notice "Cannot manage %s: permission denied" % self.name + return + end - children = Dir.entries(self.name) - - #Get rid of ignored children - if @parameters.include?(:ignore) - children = handleignore(children) - end - - added = [] - children.each { |file| - file = File.basename(file) - next if file =~ /^\.\.?$/ # skip . and .. - if child = self.newchild(file, :recurse => recurse) - unless @children.include?(child) - self.push child - added.push file + children = Dir.entries(self.name) + + #Get rid of ignored children + if @parameters.include?(:ignore) + children = handleignore(children) + end + + added = [] + children.each { |file| + file = File.basename(file) + next if file =~ /^\.\.?$/ # skip . and .. + if child = self.newchild(file, :recurse => recurse) + unless @children.include?(child) + self.push child + added.push file + end + child.retrieve end - child.retrieve - end - } - end - - # This recurses against the remote source and makes sure the local - # and remote structures match. It's run after 'localrecurse'. - def sourcerecurse(recurse) - # FIXME sourcerecurse should support purging non-remote files - source = @states[:source].source - - sourceobj, path = uri2obj(source) - - # we'll set this manually as necessary - if @arghash.include?(:create) - @arghash.delete(:create) + } end - # okay, we've got our source object; now we need to - # build up a local file structure to match the remote - # one - - server = sourceobj.server - sum = "md5" - if state = self.state(:checksum) - sum = state.checktype - end - r = false - if recurse - unless recurse == 0 - r = 1 + # This recurses against the remote source and makes sure the local + # and remote structures match. It's run after 'localrecurse'. + def sourcerecurse(recurse) + # FIXME sourcerecurse should support purging non-remote files + source = @states[:source].source + + sourceobj, path = uri2obj(source) + + # we'll set this manually as necessary + if @arghash.include?(:create) + @arghash.delete(:create) end - end - ignore = @parameters[:ignore] - - #self.warning "Listing path %s" % path.inspect - desc = server.list(path, r, ignore) - - desc.split("\n").each { |line| - file, type = line.split("\t") - next if file == "/" - name = file.sub(/^\//, '') - #self.warning "child name is %s" % name - args = {:source => source + file} - if type == file - args[:recurse] = nil + # okay, we've got our source object; now we need to + # build up a local file structure to match the remote + # one + + server = sourceobj.server + sum = "md5" + if state = self.state(:checksum) + sum = state.checktype end - self.newchild(name, args) - #self.newchild(hash, source, recurse) - #hash2child(hash, source, recurse) - } - end - - # a wrapper method to make sure the file exists before doing anything - def retrieve - if @states.include?(:source) - # This probably isn't the best place for it, but we need - # to make sure that we have a corresponding checksum state. - unless @states.include?(:checksum) - self[:checksum] = "md5" + r = false + if recurse + unless recurse == 0 + r = 1 + end end - @states[:source].retrieve - end - if @parameters.include?(:recurse) - self.recurse - end - - unless stat = self.stat(true) - self.debug "File does not exist" - @states.each { |name,state| - # We've already retreived the source, and we don't - # want to overwrite whatever it did. This is a bit - # of a hack, but oh well, source is definitely special. - next if name == :source - state.is = :notfound + ignore = @parameters[:ignore] + + #self.warning "Listing path %s" % path.inspect + desc = server.list(path, r, ignore) + + desc.split("\n").each { |line| + file, type = line.split("\t") + next if file == "/" + name = file.sub(/^\//, '') + #self.warning "child name is %s" % name + args = {:source => source + file} + if type == file + args[:recurse] = nil + end + self.newchild(name, args) + #self.newchild(hash, source, recurse) + #hash2child(hash, source, recurse) } - return end - super - end + # a wrapper method to make sure the file exists before doing anything + def retrieve + if @states.include?(:source) + # This probably isn't the best place for it, but we need + # to make sure that we have a corresponding checksum state. + unless @states.include?(:checksum) + self[:checksum] = "md5" + end + @states[:source].retrieve + end - def stat(refresh = false) - if @stat.nil? or refresh == true - begin - @stat = File.lstat(self.name) - rescue Errno::ENOENT => error - @stat = nil - rescue => error - self.debug "Failed to stat %s: %s" % - [self.name,error] - @stat = nil + if @parameters.include?(:recurse) + self.recurse end - end - return @stat - end + unless stat = self.stat(true) + self.debug "File does not exist" + @states.each { |name,state| + # We've already retreived the source, and we don't + # want to overwrite whatever it did. This is a bit + # of a hack, but oh well, source is definitely special. + next if name == :source + state.is = :notfound + } + return + end - def uri2obj(source) - sourceobj = FileSource.new - path = nil - if source =~ /^\// - source = "file://localhost/%s" % source - sourceobj.mount = "localhost" - sourceobj.local = true - end - begin - uri = URI.parse(source) - rescue => detail - raise Puppet::Error, "Could not understand source %s: %s" % - [source, detail.to_s] + super end - case uri.scheme - when "file": - unless defined? @@localfileserver - @@localfileserver = Puppet::Server::FileServer.new( - :Local => true, - :Mount => { "/" => "localhost" }, - :Config => false - ) - #@@localfileserver.mount("/", "localhost") + def stat(refresh = false) + if @stat.nil? or refresh == true + begin + @stat = File.lstat(self.name) + rescue Errno::ENOENT => error + @stat = nil + rescue => error + self.debug "Failed to stat %s: %s" % + [self.name,error] + @stat = nil + end end - sourceobj.server = @@localfileserver - path = "/localhost" + uri.path - when "puppet": - args = { :Server => uri.host } - if uri.port - args[:Port] = uri.port + + return @stat + end + + def uri2obj(source) + sourceobj = FileSource.new + path = nil + if source =~ /^\// + source = "file://localhost/%s" % source + sourceobj.mount = "localhost" + sourceobj.local = true end - # FIXME We should cache a copy of this server - #sourceobj.server = Puppet::NetworkClient.new(args) - unless @clients.include?(source) - @clients[source] = Puppet::Client::FileClient.new(args) + begin + uri = URI.parse(source) + rescue => detail + raise Puppet::Error, "Could not understand source %s: %s" % + [source, detail.to_s] end - sourceobj.server = @clients[source] - tmp = uri.path - if tmp =~ %r{^/(\w+)} - sourceobj.mount = $1 - path = tmp - #path = tmp.sub(%r{^/\w+},'') || "/" + case uri.scheme + when "file": + unless defined? @@localfileserver + @@localfileserver = Puppet::Server::FileServer.new( + :Local => true, + :Mount => { "/" => "localhost" }, + :Config => false + ) + #@@localfileserver.mount("/", "localhost") + end + sourceobj.server = @@localfileserver + path = "/localhost" + uri.path + when "puppet": + args = { :Server => uri.host } + if uri.port + args[:Port] = uri.port + end + # FIXME We should cache a copy of this server + #sourceobj.server = Puppet::NetworkClient.new(args) + unless @clients.include?(source) + @clients[source] = Puppet::Client::FileClient.new(args) + end + sourceobj.server = @clients[source] + + tmp = uri.path + if tmp =~ %r{^/(\w+)} + sourceobj.mount = $1 + path = tmp + #path = tmp.sub(%r{^/\w+},'') || "/" + else + raise Puppet::Error, "Invalid source path %s" % tmp + end else - raise Puppet::Error, "Invalid source path %s" % tmp + raise Puppet::Error, + "Got other recursive file proto %s from %s" % + [uri.scheme, source] end - else - raise Puppet::Error, - "Got other recursive file proto %s from %s" % - [uri.scheme, source] - end - return [sourceobj, path.sub(/\/\//, '/')] - end - end # Puppet.type(:pfile) + return [sourceobj, path.sub(/\/\//, '/')] + end + end # Puppet::Type::PFile + end # Puppet::Type # the filesource class can't include the path, because the path # changes for every file instance @@ -525,14 +566,4 @@ module Puppet end end -# We put all of the states in separate files, because there are so many -# of them. The order these are loaded is important, because it determines -# the order they are in the state list. -require 'puppet/type/pfile/create' -require 'puppet/type/pfile/checksum' -require 'puppet/type/pfile/source' -require 'puppet/type/pfile/uid' -require 'puppet/type/pfile/group' -require 'puppet/type/pfile/mode' -require 'puppet/type/pfile/type' # $Id$ diff --git a/lib/puppet/type/pfile/checksum.rb b/lib/puppet/type/pfile/checksum.rb index 179c1f613..33687c517 100755 --- a/lib/puppet/type/pfile/checksum.rb +++ b/lib/puppet/type/pfile/checksum.rb @@ -3,212 +3,215 @@ # This state never actually modifies the system, it only notices when the system # changes on its own. module Puppet - Puppet.type(:file).newstate(:checksum) do - desc "How to check whether a file has changed. **md5**/*lite-md5*/ - *time*/*mtime*" - @event = :file_modified + 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 + @unmanaged = true - @validtypes = %w{md5 md5lite timestamp mtime time} + @validtypes = %w{md5 md5lite timestamp mtime time} - def self.validtype?(type) - @validtypes.include?(type) - end + def self.validtype?(type) + @validtypes.include?(type) + end - def checktype - @checktypes[0] - end + def checktype + @checktypes[0] + end - def getsum(checktype) - sum = "" - case checktype - when "md5", "md5lite": - unless FileTest.file?(@parent[:path]) - #@parent.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? - self.info "Not checksumming empty file %s" % - @parent.name - sum = 0 - else - sum = Digest::MD5.hexdigest(text) - end - } - rescue Errno::EACCES => detail - self.notice "Cannot checksum %s: permission denied" % - @parent.name - @parent.delete(self.class.name) - rescue => detail - self.notice "Cannot checksum %s: %s" % - detail - @parent.delete(self.class.name) + def getsum(checktype) + sum = "" + case checktype + when "md5", "md5lite": + unless FileTest.file?(@parent[:path]) + #@parent.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? + self.info "Not checksumming empty file %s" % + @parent.name + sum = 0 + else + sum = Digest::MD5.hexdigest(text) + end + } + rescue Errno::EACCES => detail + self.notice "Cannot checksum %s: permission denied" % + @parent.name + @parent.delete(self.class.name) + rescue => detail + self.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 - 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. - munge do |value| - unless defined? @checktypes - @checktypes = [] - end - unless self.class.validtype?(value) - raise Puppet::Error, "Invalid checksum type '%s'" % value + return sum end - @checktypes << value - state = Puppet::Storage.state(self) - if hash = state[@parent[:path]] - if hash.include?(value) - return hash[value] - #@parent.debug "Found checksum %s for %s" % - # [self.should,@parent[:path]] + # Convert from the sum type to the stored checksum. + def shouldprocess(value) + unless defined? @checktypes + @checktypes = [] + end + unless self.class.validtype?(value) + raise Puppet::Error, "Invalid checksum type '%s'" % value + end + + @checktypes << value + state = Puppet::Storage.state(self) + if hash = state[@parent[:path]] + if hash.include?(value) + return hash[value] + #@parent.debug "Found checksum %s for %s" % + # [self.should,@parent[:path]] + else + #@parent.debug "Found checksum for %s but not of type %s" % + # [@parent[:path],@checktype] + return :nosum + end else - #@parent.debug "Found checksum for %s but not of type %s" % - # [@parent[:path],@checktype] + # We can't use :notfound here, because then it'll match on + # non-existent files 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 - unless defined? @checktypes - @checktypes = ["md5"] end - unless FileTest.exists?(@parent.name) - self.is = :notfound - return - end - - # Just use the first allowed check type - @is = getsum(@checktypes[0]) - - # 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 + # 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 + unless defined? @checktypes + @checktypes = ["md5"] + end - #@parent.debug "checksum state is %s" % self.is - end + unless FileTest.exists?(@parent.name) + self.is = :notfound + return + end + # Just use the first allowed check type + @is = getsum(@checktypes[0]) + + # 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 - # 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 + #@parent.debug "checksum state is %s" % self.is end - if @is == :notfound - self.retrieve - if self.insync? - self.debug "Checksum is already in sync" - return nil + # 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 - #@parent.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) - self.warning( - "File %s does not exist -- cannot checksum" % - @parent.name - ) + self.retrieve + + if self.insync? + self.debug "Checksum is already in sync" + return nil + end + #@parent.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) + self.warning( + "File %s does not exist -- cannot checksum" % + @parent.name + ) + end + return nil end - return nil end - end - # If the sums are different, then return an event. - if self.updatesum - return :file_modified - else - return nil + # If the sums are different, then return an event. + if self.updatesum + return :file_modified + else + return nil + end end - end - # Store the new sum to the state db. - def updatesum - result = false - state = Puppet::Storage.state(self) - unless state.include?(@parent.name) - self.debug "Initializing state hash" + # Store the new sum to the state db. + def updatesum + result = false + state = Puppet::Storage.state(self) + unless state.include?(@parent.name) + self.debug "Initializing state hash" - state[@parent.name] = Hash.new - end + 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 @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?(@checktypes[0]) - unless defined? @should - raise Puppet::Error.new( - ("@should is not initialized for %s, even though we " + - "found a checksum") % @parent[:path] - ) + # if we're replacing, vs. updating + if state[@parent.name].include?(@checktypes[0]) + unless defined? @should + raise Puppet::Error.new( + ("@should is not initialized for %s, even though we " + + "found a checksum") % @parent[:path] + ) + end + self.debug "Replacing %s checksum %s with %s" % + [@parent.name, state[@parent.name][@checktypes[0]],@is] + #@parent.debug "@is: %s; @should: %s" % [@is,@should] + result = true + else + @parent.debug "Creating checksum %s of type %s" % + [@is,@checktypes[0]] + result = false end - self.debug "Replacing %s checksum %s with %s" % - [@parent.name, state[@parent.name][@checktypes[0]],@is] - #@parent.debug "@is: %s; @should: %s" % [@is,@should] - result = true - else - @parent.debug "Creating checksum %s of type %s" % - [@is,@checktypes[0]] - result = false + state[@parent.name][@checktypes[0]] = @is + return result end - state[@parent.name][@checktypes[0]] = @is - return result end end end diff --git a/lib/puppet/type/pfile/create.rb b/lib/puppet/type/pfile/create.rb index 449978de7..d4c593018 100755 --- a/lib/puppet/type/pfile/create.rb +++ b/lib/puppet/type/pfile/create.rb @@ -1,104 +1,106 @@ module Puppet - Puppet.type(:file).newstate(:create) do - require 'etc' - desc "Whether to create files that don't currently exist. - **false**/*true*/*file*/*directory*" + 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 - @event = :file_created - - munge do |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 + 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 - end - def retrieve - if stat = @parent.stat(true) - @is = stat.ftype - else - @is = :notfound - end + def retrieve + if stat = @parent.stat(true) + @is = stat.ftype + else + @is = :notfound + end - #self.debug "'exists' state is %s" % self.is - end + #self.debug "'exists' state is %s" % self.is + end - def sync - event = nil - mode = @parent.should(:mode) + def sync + event = nil + mode = @parent.should(:mode) - # First, determine if a user has been specified and if so if - # that user has write access to the parent dir - asuser = nil - if @parent.should(:owner) and ! @parent.should(:owner).is_a?(Symbol) - writeable = Puppet::Util.asuser(@parent.should(:owner)) { - FileTest.writable?(File.dirname(@parent[:path])) - } + # First, determine if a user has been specified and if so if + # that user has write access to the parent dir + asuser = nil + if @parent.should(:owner) and ! @parent.should(:owner).is_a?(Symbol) + writeable = Puppet::Util.asuser(@parent.should(:owner)) { + FileTest.writable?(File.dirname(@parent[:path])) + } - # If the parent directory is writeable, then we execute - # as the user in question. Otherwise we'll rely on - # the 'owner' state to do things. - if writeable - asuser = @parent.should(:owner) + # If the parent directory is writeable, then we execute + # as the user in question. Otherwise we'll rely on + # the 'owner' state to do things. + if writeable + asuser = @parent.should(:owner) + end end - end - begin - case self.should - when "file": - # just create an empty file - Puppet::Util.asuser(asuser, @parent.should(:group)) { - if mode - File.open(@parent[:path],"w", mode) { - } - else - File.open(@parent[:path],"w") { - } - end - } - event = :file_created - when "directory": - Puppet::Util.asuser(asuser) { - if mode - Dir.mkdir(@parent.name,mode) - else - Dir.mkdir(@parent.name) + begin + case self.should + when "file": + # just create an empty file + Puppet::Util.asuser(asuser, @parent.should(:group)) { + if mode + File.open(@parent[:path],"w", mode) { + } + else + File.open(@parent[:path],"w") { + } + end + } + event = :file_created + when "directory": + Puppet::Util.asuser(asuser) { + if mode + Dir.mkdir(@parent.name,mode) + else + Dir.mkdir(@parent.name) + end + } + event = :directory_created + when :notfound: + # this is where the file should be deleted... + + # This value is only valid when we're rolling back a creation, + # so we verify that the file has not been modified since then. + unless FileTest.size(@parent.name) == 0 + raise Puppet::Error.new( + "Created file %s has since been modified; cannot roll back." + ) end - } - event = :directory_created - when :notfound: - # this is where the file should be deleted... - # This value is only valid when we're rolling back a creation, - # so we verify that the file has not been modified since then. - unless FileTest.size(@parent.name) == 0 - raise Puppet::Error.new( - "Created file %s has since been modified; cannot roll back." - ) + File.unlink(@parent.name) + else + error = Puppet::Error.new( + "Somehow got told to create a %s file" % self.should) + raise error end - - File.unlink(@parent.name) - else - error = Puppet::Error.new( - "Somehow got told to create a %s file" % self.should) - raise error + rescue => detail + raise Puppet::Error.new("Could not create %s: %s" % + [self.should, detail] + ) end - rescue => detail - raise Puppet::Error.new("Could not create %s: %s" % - [self.should, detail] - ) + return event end - return event end end end diff --git a/lib/puppet/type/pfile/group.rb b/lib/puppet/type/pfile/group.rb index 5bb297fa2..63098b892 100755 --- a/lib/puppet/type/pfile/group.rb +++ b/lib/puppet/type/pfile/group.rb @@ -1,124 +1,127 @@ # Manage file group ownership. module Puppet - Puppet.type(:file).newstate(:group) do - require 'etc' - desc "Which group should own the file. Argument can be either group - name or group ID." - @event = :inode_changed - - def id2name(id) - begin - group = Etc.getgrgid(id) - rescue ArgumentError - return nil + 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 id2name(id) + begin + group = Etc.getgrgid(id) + rescue ArgumentError + return nil + end + if group.gid == "" + return nil + else + return group.name + end end - if group.gid == "" - return nil - else - return group.name + + # We want to print names, not numbers + def is_to_s + id2name(@is) || @is end - end - # We want to print names, not numbers - def is_to_s - id2name(@is) || @is - end + def should_to_s + id2name(self.should) || self.should + end - def should_to_s - id2name(self.should) || self.should - end + def retrieve + stat = @parent.stat(true) - def retrieve - stat = @parent.stat(true) + self.is = stat.gid + end - self.is = stat.gid - end + def shouldprocess(value) + method = nil + gid = nil + gname = nil - munge do |value| - method = nil - gid = nil - gname = nil + if value.is_a?(Integer) + method = :getgrgid + else + method = :getgrnam + 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 - 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 + #unless Process.uid == 0 + # groups = %x{groups}.chomp.split(/\s/) + # unless groups.include?(gname) + # self.notice "Cannot chgrp: not in group %s" % gname + # raise Puppet::Error.new( + # "Cannot chgrp: not in group %s" % gname) + # end #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) + if gid.nil? + raise Puppet::Error.new( + "Nil gid for %s" % @parent.name) + else + return gid + end end - #unless Process.uid == 0 - # groups = %x{groups}.chomp.split(/\s/) - # unless groups.include?(gname) - # self.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 - if @is == :notfound - @parent.stat(true) - self.retrieve - + # 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 if @is == :notfound - self.err "File '%s' does not exist; cannot chgrp" % - @parent[:path] - return nil + @parent.stat(true) + self.retrieve + + if @is == :notfound + self.err "File '%s' does not exist; cannot chgrp" % + @parent[:path] + return nil + end + + if self.insync? + return nil + end end - if self.insync? - return nil + 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 - - 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 diff --git a/lib/puppet/type/pfile/mode.rb b/lib/puppet/type/pfile/mode.rb index 297e5cb1c..7ef04441d 100755 --- a/lib/puppet/type/pfile/mode.rb +++ b/lib/puppet/type/pfile/mode.rb @@ -2,125 +2,128 @@ # for specification (e.g., u+rwx, or -0011), but for now only supports # specifying the full mode. module Puppet - Puppet.type(:file).newstate(:mode) do - require 'etc' - desc "Mode the file should be. Currently relatively limited: - you must specify the exact mode the file should be." - @event = :inode_changed + 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. Other - # valid values are symbols, basically - def is_to_s - case @is - when Integer - return "%o" % @is - when Symbol - return @is - else - raise Puppet::DevError, "Invalid 'is' value for mode: %s" % - @is.inspect + # Our modes are octal, so make sure they print correctly. Other + # valid values are symbols, basically + def is_to_s + case @is + when Integer + return "%o" % @is + when Symbol + return @is + else + raise Puppet::DevError, "Invalid 'is' value for mode: %s" % + @is.inspect + end end - end - def should_to_s - case self.should - when Integer - return "%o" % self.should - when Symbol - return self.should - else - raise Puppet::DevError, "Invalid 'should' value for mode: %s" % - self.should.inspect + def should_to_s + case self.should + when Integer + return "%o" % self.should + when Symbol + return self.should + else + raise Puppet::DevError, "Invalid 'should' value for mode: %s" % + self.should.inspect + end end - end - munge do |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-9]+$/ - raise Puppet::Error, "File modes can only be numbers" - end - unless value =~ /^0/ - value = "0" + value - end - begin - value = Integer(value) - rescue ArgumentError => detail - raise Puppet::DevError, "Could not convert %s to integer" % - value.inspect + 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-9]+$/ + raise Puppet::Error, "File modes can only be numbers" + end + unless value =~ /^0/ + value = "0" + value + end + begin + value = Integer(value) + rescue ArgumentError => detail + raise Puppet::DevError, "Could not convert %s to integer" % + value.inspect + end end - end - return value - end + 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 + # 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 - end - return value - 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) } + 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 - else - self.is = :notfound - end - #self.debug "chmod state is %o" % self.is - end + #self.debug "chmod state is %o" % self.is + end - def sync - if @is == :notfound - @parent.stat(true) - self.retrieve - #self.debug "%s: after refresh, is '%s'" % [self.class.name,@is] + def sync if @is == :notfound - self.info "File does not exist; cannot set mode" % - @parent.name - return nil - end + @parent.stat(true) + self.retrieve + #self.debug "%s: after refresh, is '%s'" % [self.class.name,@is] + if @is == :notfound + self.info "File does not exist; cannot set mode" % + @parent.name + return nil + end - if self.insync? - # we're already in sync - return nil + if self.insync? + # we're already in sync + return nil + end end - end - mode = self.should + mode = self.should - if mode == :notfound - # This is really only valid for create states... - return nil - end + 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 + 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 - return :inode_changed end end end diff --git a/lib/puppet/type/pfile/source.rb b/lib/puppet/type/pfile/source.rb index b8f6e3045..a035878b1 100755 --- a/lib/puppet/type/pfile/source.rb +++ b/lib/puppet/type/pfile/source.rb @@ -1,262 +1,262 @@ module Puppet - + class State # Copy files from a local or remote source. - Puppet.type(:file).newstate(:source) do - PINPARAMS = [:mode, :type, :owner, :group, :checksum] - - attr_accessor :source, :local - desc "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*." - - # 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 - self.err "Could not describe %s: %s" % - [path, detail] - return nil - end + 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 - args = {} - PINPARAMS.zip( - desc.split("\t") - ).each { |param, value| - if value =~ /^[0-9]+$/ - value = value.to_i - end - unless value.nil? - args[param] = value + begin + desc = server.describe(path) + rescue NetworkClientError => detail + self.err "Could not describe %s: %s" % + [path, detail] + return nil end - } - # we can't manage ownership as root, so don't even try - unless Process.uid == 0 - args.delete(:owner) - end - - if args.empty? - return nil - else - return args - end - end + args = {} + Puppet::Type::PFile::PINPARAMS.zip( + desc.split("\t") + ).each { |param, value| + if value =~ /^[0-9]+$/ + value = value.to_i + end + unless value.nil? + args[param] = value + 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 + # we can't manage ownership as root, so don't even try + unless Process.uid == 0 + args.delete(:owner) + end - unless defined? @shouldorig - raise Puppet::DevError, "No sources defined for %s" % - @parent.name + if args.empty? + return nil + else + return args + end 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 + # 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 - } - 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 + + # 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 - } - - # 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 + + # 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 - @is = sum.is else + self.info "File does not have checksum" @is = :notfound end - else - self.info "File does not have checksum" - @is = :notfound - end - @should = [@stats[:checksum]] + @should = [@stats[:checksum]] - if state = @parent.state(:create) - unless state.should == "file" - self.notice( - "File %s had both create and source enabled" % - @parent.name - ) - @parent.delete(:create) + if state = @parent.state(:create) + unless state.should == "file" + self.notice( + "File %s had both create and source enabled" % + @parent.name + ) + @parent.delete(:create) + end 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" + # 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.clear + @is = true + # FIXME We should at least support symlinks, I would think... else - @parent[:create] = "directory" - @parent.state(:create).retrieve + self.err "Cannot use files of type %s as sources" % + @stats[:type] + @should = nil + @is = true end - # we'll let the :create state do our work - @should.clear - @is = true - # FIXME We should at least support symlinks, I would think... - else - self.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'. - munge do |source| - unless @parent.uri2obj(source) - raise Puppet::Error, "Invalid source %s" % source - 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 + 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 - end - def sync - if @is == :notdescribed - self.retrieve # try again + def sync if @is == :notdescribed - @parent.log "Could not retreive information on %s" % - @parent.name - return nil + 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 - if @is == @should - return nil + + 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 - end - unless @stats[:type] == "file" - if @stats[:type] == "directory" - [@parent.name, @is.inspect, @should.inspect] + unless defined? @source + raise Puppet::DevError, "Somehow source is still undefined" 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) - sourceobj, path = @parent.uri2obj(@source) + begin + contents = sourceobj.server.retrieve(path) + rescue NetworkClientError => detail + self.err "Could not retrieve %s: %s" % + [path, detail] + return nil + end - begin - contents = sourceobj.server.retrieve(path) - rescue NetworkClientError => detail - self.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 - # 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 == "" + self.notice "Could not retrieve contents for %s" % + @source + end - if contents == "" - self.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 - 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] - # 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 - # 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 - # 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 - 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 + self.err "Could not remove %s for replacing: %s" % + [@parent.name, detail] + end + end - if FileTest.exists?(@parent.name) begin - File.unlink(@parent.name) + File.rename(@parent.name + ".puppettmp", @parent.name) rescue => detail - self.err "Could not remove %s for replacing: %s" % + self.err "Could not rename tmp %s for replacing: %s" % [@parent.name, detail] end - end - begin - File.rename(@parent.name + ".puppettmp", @parent.name) - rescue => detail - self.err "Could not rename tmp %s for replacing: %s" % - [@parent.name, detail] + return :file_changed end - - return :file_changed end end end diff --git a/lib/puppet/type/pfile/type.rb b/lib/puppet/type/pfile/type.rb index 7d761c40b..1d03634e7 100755 --- a/lib/puppet/type/pfile/type.rb +++ b/lib/puppet/type/pfile/type.rb @@ -1,26 +1,29 @@ module Puppet - Puppet.type(:file).newstate(:type) do - require 'etc' - desc "A read-only state to check the file type." + class State + class PFileType < Puppet::State + require 'etc' + @doc = "A read-only state to check the file type." + @name = :type - #munge do |value| - # raise Puppet::Error, ":type is read-only" - #end - - def retrieve - if stat = @parent.stat(true) - @is = stat.ftype - else - @is = :notfound + 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 + # so this state is never marked out of sync + @should = [@is] + end - def sync - raise Puppet::Error, ":type is read-only" + def sync + raise Puppet::Error, ":type is read-only" + end end end end diff --git a/lib/puppet/type/pfile/uid.rb b/lib/puppet/type/pfile/uid.rb index 3f1add774..8a2f7ec79 100755 --- a/lib/puppet/type/pfile/uid.rb +++ b/lib/puppet/type/pfile/uid.rb @@ -1,161 +1,164 @@ module Puppet - Puppet.type(:file).newstate(:owner) do - require 'etc' - desc "To whom the file should belong. Argument can be user name or - user ID." - @event = :inode_changed - - def id2name(id) - if id.is_a?(Symbol) - return id.to_s - end - begin - user = Etc.getpwuid(id) - rescue TypeError - return nil - rescue ArgumentError - return nil - end - if user.uid == "" - return nil - else - return user.name - end - end - - def name2id(value) - if value.is_a?(Symbol) - return value.to_s - end - begin - user = Etc.getpwnam(value) + 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 id2name(id) + if id.is_a?(Symbol) + return id.to_s + end + begin + user = Etc.getpwuid(id) + rescue TypeError + return nil + rescue ArgumentError + return nil + end if user.uid == "" return nil + else + return user.name end - return user.uid - rescue ArgumentError => detail - return nil end - end - # Determine if the user is valid, and if so, return the UID - def validuser?(value) - if value =~ /^\d+$/ - value = value.to_i + def name2id(value) + if value.is_a?(Symbol) + return value.to_s + end + begin + user = Etc.getpwnam(value) + if user.uid == "" + return nil + end + return user.uid + rescue ArgumentError => detail + return nil + end end - if value.is_a?(Integer) - # verify the user is a valid user - if tmp = id2name(value) - return value - else - return false + # Determine if the user is valid, and if so, return the UID + def validuser?(value) + if value =~ /^\d+$/ + value = value.to_i end - else - if tmp = name2id(value) - return tmp + + if value.is_a?(Integer) + # verify the user is a valid user + if tmp = id2name(value) + return value + else + return false + end else - return false + if tmp = name2id(value) + return tmp + else + return false + end end end - end - - # We want to print names, not numbers - def is_to_s - id2name(@is) || @is - end - def should_to_s - case self.should - when Symbol - self.should.to_s - when Integer - id2name(self.should) || self.should - when String - self.should - else - raise Puppet::DevError, "Invalid uid type %s(%s)" % - [self.should.class, self.should] + # We want to print names, not numbers + def is_to_s + id2name(@is) || @is end - end - def retrieve - unless stat = @parent.stat(true) - @is = :notfound - return + def should_to_s + case self.should + when Symbol + self.should.to_s + when Integer + id2name(self.should) || self.should + when String + self.should + else + raise Puppet::DevError, "Invalid uid type %s(%s)" % + [self.should.class, self.should] + end end - self.is = stat.uid + def retrieve + unless stat = @parent.stat(true) + @is = :notfound + return + end - # On OS X, files that are owned by -2 get returned as really - # large UIDs instead of negative ones. This isn't a Ruby bug, - # it's an OS X bug, since it shows up in perl, too. - if @is > 120000 - self.warning "current state is silly: %s" % @is - @is = :notfound - end - end + self.is = stat.uid - # If we're not root, we can check the values but we cannot change - # them. We can't really do any processing here, because users - # might not exist yet. FIXME There's still a bit of a problem here - # if the user's UID changes at run time, but we're just going to - # have to be okay with that for now, unfortunately. - munge do |value| - if tmp = self.validuser?(value) - return tmp - else - return value + # On OS X, files that are owned by -2 get returned as really + # large UIDs instead of negative ones. This isn't a Ruby bug, + # it's an OS X bug, since it shows up in perl, too. + if @is > 120000 + self.warning "current state is silly: %s" % @is + @is = :notfound + end end - end - def sync - unless Process.uid == 0 - unless defined? @@notifieduid - self.notice "Cannot manage ownership unless running as root" - #@parent.delete(self.name) - @@notifieduid = true + # If we're not root, we can check the values but we cannot change + # them. We can't really do any processing here, because users + # might not exist yet. FIXME There's still a bit of a problem here + # if the user's UID changes at run time, but we're just going to + # have to be okay with that for now, unfortunately. + def shouldprocess(value) + if tmp = self.validuser?(value) + return tmp + else + return value end - return nil end - user = nil - unless user = self.validuser?(self.should) - tmp = self.should - unless defined? @@usermissing - @@usermissing = {} + def sync + unless Process.uid == 0 + unless defined? @@notifieduid + self.notice "Cannot manage ownership unless running as root" + #@parent.delete(self.name) + @@notifieduid = true + end + return nil end - if @@usermissing.include?(tmp) - @@usermissing[tmp] += 1 - else - self.notice "user %s does not exist" % tmp - @@usermissing[tmp] = 1 - return nil + user = nil + unless user = self.validuser?(self.should) + tmp = self.should + unless defined? @@usermissing + @@usermissing = {} + end + + if @@usermissing.include?(tmp) + @@usermissing[tmp] += 1 + else + self.notice "user %s does not exist" % tmp + @@usermissing[tmp] = 1 + return nil + end end - end - if @is == :notfound - @parent.stat(true) - self.retrieve if @is == :notfound - self.info "File does not exist; cannot set owner" - return nil + @parent.stat(true) + self.retrieve + if @is == :notfound + self.info "File does not exist; cannot set owner" + return nil + end + if self.insync? + return nil + end + #self.debug "%s: after refresh, is '%s'" % [self.class.name,@is] end - if self.insync? - return nil + + begin + File.chown(user, nil, @parent[:path]) + rescue => detail + raise Puppet::Error, "Failed to set owner to '%s': %s" % + [user, detail] end - #self.debug "%s: after refresh, is '%s'" % [self.class.name,@is] - end - begin - File.chown(user, nil, @parent[:path]) - rescue => detail - raise Puppet::Error, "Failed to set owner to '%s': %s" % - [user, detail] + return :inode_changed end - - return :inode_changed end end end diff --git a/lib/puppet/type/pfilebucket.rb b/lib/puppet/type/pfilebucket.rb index d17f681af..7d38a612a 100755 --- a/lib/puppet/type/pfilebucket.rb +++ b/lib/puppet/type/pfilebucket.rb @@ -1,76 +1,80 @@ +# An interface for managing filebuckets from puppet + +# $Id$ + require 'puppet/server/filebucket' module Puppet - newtype(:filebucket) do - attr_reader :bucket + class Type + class PFileBucket < Type + attr_reader :bucket - @doc = "A repository for backing up files. If no filebucket is - defined, then files will be backed up in their current directory, - but the filebucket can be either a host- or site-global repository - for backing up. It stores files and returns the MD5 sum, which - can later be used to retrieve the file if restoration becomes - necessary. A filebucket does not do any work itself; instead, - it can be specified as the value of *backup* in a **file** object." + @states = [] - @states = [] + @parameters = [ + :name, + :server, + :path, + :port + ] - newparam(:name) do - desc "The name of the filebucket." - isnamevar - end - - newparam(:server) do - desc "The server providing the filebucket. If this is - not specified, then the bucket is local and *path* must be - specified." - end + @doc = "A repository for backing up files. If no filebucket is + defined, then files will be backed up in their current directory, + but the filebucket can be either a host- or site-global repository + for backing up. It stores files and returns the MD5 sum, which + can later be used to retrieve the file if restoration becomes + necessary. A filebucket does not do any work itself; instead, + it can be specified as the value of *backup* in a **file** object." - newparam(:port) do - desc "The port on which the remote server is listening. + @paramdoc[:name] = "The name of the filebucket." + @paramdoc[:server] = "The server providing the filebucket. If this is + not specified, then the bucket is local and *path* must be specified." + @paramdoc[:port] = "The port on which the remote server is listening. Defaults to the normal Puppet port, %s." % Puppet[:masterport] - end - - newparam(:path) do - desc "The path to the local filebucket. If this is + @paramdoc[:path] = "The path to the local filebucket. If this is not specified, then the bucket is remote and *server* must be specified." - end - # get the actual filebucket object - def self.bucket(name) - oname, object = @objects.find { |oname, o| oname == name } - return object.bucket - end + @name = :filebucket + @namevar = :name - def initialize(hash) - super + # get the actual filebucket object + def self.bucket(name) + oname, object = @objects.find { |oname, o| oname == name } + return object.bucket + end - if @parameters.include?(:server) - @parameters[:port] ||= FileBucket::DEFAULTPORT - begin - @bucket = Puppet::Client::Dipper.new( - :Server => @parameters[:server], - :Port => @parameters[:port] - ) - rescue => detail - raise Puppet::Error.new( - "Could not create remote filebucket: %s" % detail - ) - end - else - @parameters[:path] ||= Puppet[:bucketdir] - begin - @bucket = Puppet::Client::Dipper.new( - :Path => @parameters[:path] - ) - rescue => detail - raise Puppet::Error.new( - "Could not create local filebucket: %s" % detail - ) + def initialize(hash) + super + + if @parameters.include?(:server) + @parameters[:port] ||= FileBucket::DEFAULTPORT + begin + @bucket = Puppet::Client::Dipper.new( + :Server => @parameters[:server], + :Port => @parameters[:port] + ) + rescue => detail + raise Puppet::Error.new( + "Could not create remote filebucket: %s" % detail + ) + end + else + @parameters[:path] ||= Puppet[:bucketdir] + begin + @bucket = Puppet::Client::Dipper.new( + :Path => @parameters[:path] + ) + rescue => detail + raise Puppet::Error.new( + "Could not create local filebucket: %s" % detail + ) + end end end - end - end + + end + end end # $Id$ diff --git a/lib/puppet/type/pprocess.rb b/lib/puppet/type/pprocess.rb index dad39cd2c..c2038987f 100644 --- a/lib/puppet/type/pprocess.rb +++ b/lib/puppet/type/pprocess.rb @@ -89,7 +89,7 @@ module Puppet :pattern => :pattern }) - end # Puppet.type(:pprocess) + end # Puppet::Type::PProcess end # Puppet::Type end diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index d8c4c6bd2..24b5a2492 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -5,64 +5,58 @@ # which is why they have a search path for initscripts and such 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*" + @name = :enabled - newtype(:service) do - @doc = "Manage running services. Rather than supporting managing - individual processes, puppet uses init scripts to simplify - specification of how to start, stop, or test processes. The - `path` parameter is provided to enable creation of multiple - init script directories, including supporting them for normal - users." - attr_reader :stat - -# newstate(:enabled) do -# desc "Whether a service should be enabled to start at boot. -# **true**/*false*/*runlevel*" -# -# def retrieve -# unless @parent.respond_to?(:enabled?) -# raise Puppet::Error, "Service %s does not support enabling" -# end -# @is = @parent.enabled? -# end -# -# munge do |should| -# @runlevel = nil -# case should -# when true: return :enabled -# when false: return :disabled -# when /^\d+$/: -# @runlevel = should -# return :enabled -# else -# raise Puppet::Error, "Invalid 'enabled' value %s" % should -# end -# end -# -# def sync -# case self.should -# when :enabled -# unless @parent.respond_to?(:enable) -# raise Puppet::Error, "Service %s does not support enabling" -# end -# @parent.enable(@runlevel) -# return :service_enabled -# when :disabled -# unless @parent.respond_to?(:disable) -# raise Puppet::Error, -# "Service %s does not support disabling" -# end -# @parent.disable -# return :service_disabled -# end -# end -# end + def retrieve + unless @parent.respond_to?(:enabled?) + raise Puppet::Error, "Service %s does not support enabling" + end + @is = @parent.enabled? + end + + def shouldprocess(should) + @runlevel = nil + case should + when true: return :enabled + when false: return :disabled + when /^\d+$/: + @runlevel = should + return :enabled + else + raise Puppet::Error, "Invalid 'enabled' value %s" % should + end + end + + def sync + case self.should + when :enabled + unless @parent.respond_to?(:enable) + raise Puppet::Error, "Service %s does not support enabling" + end + @parent.enable(@runlevel) + return :service_enabled + when :disabled + unless @parent.respond_to?(:disable) + raise Puppet::Error, + "Service %s does not support disabling" + end + @parent.disable + return :service_disabled + end + end + end # Handle whether the service should actually be running right now. - newstate(:running) do - desc "Whether a service should be running. **true**/*false*" + class ServiceRunning < State + @doc = "Whether a service should be running. **true**/*false*" + @name = :running - munge do |should| + def shouldprocess(should) case should when false,0,"0", "stopped", :stopped: should = :stopped @@ -87,317 +81,260 @@ module Puppet case self.should when :running @parent.start - return :service_started + event = :service_started when :stopped @parent.stop - return :service_stopped + event = :service_stopped else self.debug "Not running '%s' and shouldn't be running" % self end end end + end - newparam(:type) do - desc "The service type" - - defaultto { @parent.class.defaulttype } - - # Make sure we've got the actual module, not just a string - # representing the module. - munge do |type| - if type.is_a?(String) - type = @parent.class.svctype(type.intern) - end - Puppet.debug "Service type is %s" % type.name - @parent.extend(type) - - return type - end - end - newparam(:binary) do - desc "The path to the daemon. This is only used for + class Type + class Service < Type + attr_reader :stat + @states = [ + Puppet::State::ServiceRunning + ] + @parameters = [ + :binary, + :hasstatus, + :name, + :path, + :pattern, + :restart, + :start, + :status, + :stop, + :type + ] + + @paramdoc[:binary] = "The path to the daemon. This is only used for systems that do not support init scripts." - end - newparam(:hasstatus) do - desc "Declare the the service's init script has a + @paramdoc[:hasstatus] = "Declare the the service's init script has a functional status command. This is assumed to be default for most systems, although there might be platforms on which this is assumed to be true." - end - newparam(:name) do - desc "The name of the service to run. This name + @paramdoc[:name] = "The name of the service to run. This name is used to find the init script in the search path." - isnamevar - end - newparam(:path) do - desc "The search path for finding init scripts. + @paramdoc[:path] = "The search path for finding init scripts. There is currently no default, but hopefully soon there will be a reasonable default for all platforms." - - munge do |value| - paths = [] - if value.is_a?(Array) - paths += value.flatten.collect { |p| - p.split(":") - }.flatten - else - paths = value.split(":") - end - - paths.each do |path| - if FileTest.directory?(path) - next - end - unless FileTest.directory?(path) - @parent.info("Search path %s is not a directory" % [path]) - end - unless FileTest.exists?(path) - @parent.info("Search path %s does not exist" % [path]) - end - paths.delete(path) - end - - paths - end - end - newparam(:pattern) do - desc "The pattern to search for in the process table. + @paramdoc[:pattern] = "The pattern to search for in the process table. This is used for stopping services on platforms that do not support init scripts, and is also used for determining service status on those service whose init scripts do not include a status command." - defaultto { @parent.name } - end - newparam(:restart) do - desc "Specify a *restart* command manually. If left + @paramdoc[:restart] = "Specify a *restart* command manually. If left unspecified, the restart method will be determined automatically." - end - newparam(:start) do - desc "Specify a *start* command manually. If left + @paramdoc[:start] = "Specify a *start* command manually. If left unspecified, the start method will be determined automatically." - end - newparam(:status) do - desc "Specify a *status* command manually. If left + @paramdoc[:status] = "Specify a *status* command manually. If left unspecified, the status method will be determined automatically." - end - - newparam(:stop) do - desc "Specify a *stop* command manually. If left + @paramdoc[:stop] = "Specify a *stop* command manually. If left unspecified, the stop method will be determined automatically." - end - # Create new subtypes of service management. - def self.newsvctype(name, parent = nil, &block) - if parent - parent = self.svctype(parent) + @doc = "Manage running services. Rather than supporting managing + individual processes, puppet uses init scripts to simplify + specification of how to start, stop, or test processes. The + `path` parameter is provided to enable creation of multiple + init script directories, including supporting them for normal + users." + @name = :service + @namevar = :name + + # Return the service type we're using. Default to the Service + # class itself, but could be set to a module. + class << self + attr_accessor :svctype end - svcname = name - mod = Module.new - # Add our parent, if it exists - if parent - mod.send(:include, parent) - end + # Retrieve the default type for the current platform. + def self.defaulttype + unless defined? @defsvctype + @defsvctype = nil + os = Facter["operatingsystem"].value + case os + when "Linux": + case Facter["distro"].value + when "Debian": + @defsvctype = Puppet::ServiceTypes::DebianSvc + end + when "SunOS": + release = Float(Facter["operatingsystemrelease"].value) + if release < 5.10 + @defsvctype = Puppet::ServiceTypes::InitSvc + else + @defsvctype = Puppet::ServiceTypes::SMFSvc + end + end - # And now define the support methods - code = %{ - def self.name - "#{svcname}" + unless @defsvctype + Puppet.notice "Defaulting to base service type" + @defsvctype = Puppet::ServiceTypes::BaseSvc + end end - def self.to_s - "SvcType(#{svcname})" - end + return @defsvctype + end - def svctype - "#{svcname}" + # Execute a command. Basically just makes sure it exits with a 0 + # code. + def execute(type, cmd) + output = %x(#{cmd} 2>&1) + unless $? == 0 + raise Puppet::Error, "Could not %s %s: %s" % + [type, self.name, output.chomp] end - } - - mod.module_eval(code) - - mod.module_eval(&block) + end - @modules ||= Hash.new do |hash, key| - if key.is_a?(String) - key = key.intern + # Get the process ID for a running process. Requires the 'pattern' + # parameter. + def getpid + unless self[:pattern] + raise Puppet::Error, + "Either a stop command or a pattern must be specified" end - - if hash.include?(key) - hash[key] - else - nil + ps = Facter["ps"].value + unless ps and ps != "" + raise Puppet::Error, + "You must upgrade Facter to a version that includes 'ps'" end + regex = Regexp.new(self[:pattern]) + IO.popen(ps) { |table| + table.each { |line| + if regex.match(line) + ary = line.sub(/^\s+/, '').split(/\s+/) + return ary[1] + end + } + } + + return nil end - @modules[name] = mod - end - # Retrieve a service type. - def self.svctype(name) - @modules[name] - end + # Initialize the service. This is basically responsible for merging + # in the right module. + def initialize(hash) + # We have to extend the object before we call 'super', so that + # the parameter methods are called correctly. + type = hash[:type] || + hash["type"] || + self.class.defaulttype - # Retrieve the default type for the current platform. - def self.defaulttype - unless defined? @defsvctype - @defsvctype = nil - os = Facter["operatingsystem"].value - case os - when "Linux": - case Facter["distro"].value - when "Debian": - @defsvctype = self.svctype(:debian) - else - @defsvctype = self.svctype(:init) - end - when "SunOS": - release = Facter["operatingsystemrelease"].value - if release.sub(/5\./,'').to_f < 10 - @defsvctype = self.svctype(:init) - else - @defsvctype = self.svctype(:smf) - end + if type.is_a?(String) + type = type2module(type) end - unless @defsvctype - Puppet.notice "Defaulting to base service type" - @defsvctype = self.svctype(:base) - end - end + # Extend the object with the service type + #self.info "extending with %s" % type + self.extend(type) - Puppet.debug "Default service type is %s" % @defsvctype.name + super - return @defsvctype - end + unless @parameters.include?(:pattern) + # default to using the service name as the pattern + self[:pattern] = self.name + end - # Execute a command. Basically just makes sure it exits with a 0 - # code. - def execute(type, cmd) - self.info "Executing %s" % cmd.inspect - output = %x(#{cmd} 2>&1) - unless $? == 0 - raise Puppet::Error, "Could not %s %s: %s" % - [type, self.name, output.chomp] + # and then see if it needs to be checked + if self.respond_to?(:configchk) + self.configchk + end end - end - # Get the process ID for a running process. Requires the 'pattern' - # parameter. - def getpid - unless self[:pattern] - raise Puppet::Error, - "Either a stop command or a pattern must be specified" - end - ps = Facter["ps"].value - unless ps and ps != "" - raise Puppet::Error, - "You must upgrade Facter to a version that includes 'ps'" + # Retrieve the service type. + def type2module(type) + case type + when "smf": + return Puppet::ServiceTypes::SMFSvc + when "init": + return Puppet::ServiceTypes::InitSvc + when "launchd": + #return Puppet::ServiceTypes::LaunchDSvc + else + raise Puppet::Error, "Invalid service type %s" % type + end end - regex = Regexp.new(self[:pattern]) - IO.popen(ps) { |table| - table.each { |line| - if regex.match(line) - ary = line.sub(/^\s+/, '').split(/\s+/) - return ary[1] - end - } - } - - return nil - end - # Initialize the service. This is basically responsible for merging - # in the right module. - def initialize(hash) - super - - # and then see if it needs to be checked - if self.respond_to?(:configchk) - self.configchk + # Basically just a synonym for restarting. Used to respond + # to events. + def refresh + self.restart end - end - # Retrieve the service type. - def type2module(type) - self.class.svctype(type) - end - - # Basically just a synonym for restarting. Used to respond - # to events. - def refresh - self.restart - end - - # How to restart the process. - def restart - if self[:restart] or self.respond_to?(:restartcmd) - cmd = self[:restart] || self.restartcmd - self.execute("restart", cmd) - else - self.stop - self.start + # How to restart the process. + def restart + if self[:restart] or self.respond_to?(:restartcmd) + cmd = self[:restart] || self.restartcmd + self.execute("restart", cmd) + else + self.stop + self.start + end end - end - # Check if the process is running. Prefer the 'status' parameter, - # then 'statuscmd' method, then look in the process table. We give - # the object the option to not return a status command, which might - # happen if, for instance, it has an init script (and thus responds to - # 'statuscmd') but does not have 'hasstatus' enabled. - def status - if self[:status] or ( - self.respond_to?(:statuscmd) and self.statuscmd - ) - cmd = self[:status] || self.statuscmd - self.info "Executing %s" % cmd.inspect - output = %x(#{cmd} 2>&1) - self.debug "%s status returned %s" % - [self.name, output.inspect] - if $? == 0 + # Check if the process is running. Prefer the 'status' parameter, + # then 'statuscmd' method, then look in the process table. We give + # the object the option to not return a status command, which might + # happen if, for instance, it has an init script (and thus responds to + # 'statuscmd') but does not have 'hasstatus' enabled. + def status + if self[:status] or ( + self.respond_to?(:statuscmd) and self.statuscmd + ) + cmd = self[:status] || self.statuscmd + output = %x(#{cmd} 2>&1) + self.debug "%s status returned %s" % + [self.name, output] + if $? == 0 + return :running + else + return :stopped + end + elsif pid = self.getpid return :running else return :stopped end - elsif pid = self.getpid - return :running - else - return :stopped end - end - # Run the 'start' parameter command, or the specified 'startcmd'. - def start - cmd = self[:start] || self.startcmd - self.execute("start", cmd) - end + # Run the 'start' parameter command, or the specified 'startcmd'. + def start + cmd = self[:start] || self.startcmd + self.execute("start", cmd) + end - # Stop the service. If a 'stop' parameter is specified, it - # takes precedence; otherwise checks if the object responds to - # a 'stopcmd' method, and if so runs that; otherwise, looks - # for the process in the process table. - # This method will generally not be overridden by submodules. - def stop - if self[:stop] - return self[:stop] - elsif self.respond_to?(:stopcmd) - self.execute("stop", self.stopcmd) - else - pid = getpid - unless pid - self.info "%s is not running" % self.name - return false - end - output = %x("kill #{pid} 2>&1") - if $? != 0 - raise Puppet::Error, - "Could not kill %s, PID %s: %s" % - [self.name, pid, output] + # Stop the service. If a 'stop' parameter is specified, it + # takes precedence; otherwise checks if the object responds to + # a 'stopcmd' method, and if so runs that; otherwise, looks + # for the process in the process table. + # This method will generally not be overridden by submodules. + def stop + if self[:stop] + return self[:stop] + elsif self.respond_to?(:stopcmd) + self.execute("stop", self.stopcmd) + else + pid = getpid + unless pid + self.info "%s is not running" % self.name + return false + end + output = %x("kill #{pid} 2>&1") + if $? != 0 + raise Puppet::Error, + "Could not kill %s, PID %s: %s" % + [self.name, pid, output] + end + return true end - return true end - end - end + end + end end # Load all of the different service types. We could probably get away with diff --git a/lib/puppet/type/service/base.rb b/lib/puppet/type/service/base.rb index f84fa85dc..6c0642541 100755 --- a/lib/puppet/type/service/base.rb +++ b/lib/puppet/type/service/base.rb @@ -1,12 +1,17 @@ -Puppet.type(:service).newsvctype(:base) do - # The command used to start. Generated if the 'binary' argument - # is passed. - def startcmd - if self[:binary] - return self[:binary] - else - raise Puppet::Error, - "Services must specify a start command or a binary" +module Puppet + module ServiceTypes + module BaseSvc + + # The command used to start. Generated if the 'binary' argument + # is passed. + def startcmd + if self[:binary] + return self[:binary] + else + raise Puppet::Error, + "Services must specify a start command or a binary" + end + end end end end diff --git a/lib/puppet/type/service/debian.rb b/lib/puppet/type/service/debian.rb index 37c33d333..aa7303d18 100755 --- a/lib/puppet/type/service/debian.rb +++ b/lib/puppet/type/service/debian.rb @@ -2,43 +2,49 @@ require 'puppet/type/service/init' # Manage debian services. Start/stop is the same as InitSvc, but enable/disable # is special. -Puppet.type(:service).newsvctype(:debian, :init) do - # Remove the symlinks - def disable - output = %x{update-rc.d -f #{self.name} remove 2>/dev/null} +module Puppet + module ServiceTypes + module DebianSvc + include Puppet::ServiceTypes::InitSvc + + # Remove the symlinks + def disable + output = %x{update-rc.d -f #{self.name} remove 2>/dev/null} - unless $? == 0 - raise Puppet::Error, "Could not disable %s: %s" % - [self.name, output] - end - end + unless $? == 0 + raise Puppet::Error, "Could not disable %s: %s" % + [self.name, output] + end + end - def enabled? - output = %x{update-rc.d -n -f #{self.name} remove 2>/dev/null} - unless $? == 0 - raise Puppet::Error, "Could not check %s: %s" % - [self.name, output] - end + def enabled? + output = %x{update-rc.d -n -f #{self.name} remove 2>/dev/null} + unless $? == 0 + raise Puppet::Error, "Could not check %s: %s" % + [self.name, output] + end - # If it's enabled, then it will print output showing removal of - # links. - if output =~ /etc\/rc\d.d/ - return true - else - return false - end - end + # If it's enabled, then it will print output showing removal of + # links. + if output =~ /etc\/rc\d.d/ + return true + else + return false + end + end - def enable(runlevel) - if runlevel - raise Puppet::Error, "Specification of runlevels is not supported" - else - output = %x{update-rc.d #{self.name} defaults 2>/dev/null} - end + def enable(runlevel) + if runlevel + raise Puppet::Error, "Specification of runlevels is not supported" + else + output = %x{update-rc.d #{self.name} defaults 2>/dev/null} + end - unless $? == 0 - raise Puppet::Error, "Could not check %s: %s" % - [self.name, output] + unless $? == 0 + raise Puppet::Error, "Could not check %s: %s" % + [self.name, output] + end + end end end end diff --git a/lib/puppet/type/service/init.rb b/lib/puppet/type/service/init.rb index d47c3b969..27e0d779b 100755 --- a/lib/puppet/type/service/init.rb +++ b/lib/puppet/type/service/init.rb @@ -1,145 +1,145 @@ -# The standard init-based service type. Many other service types are -# customizations of this module. -Puppet.type(:service).newsvctype(:init) do - - # Set the default init directory. - Puppet.type(:service).attrclass(:path).defaultto do - case Facter["operatingsystem"].value - when "FreeBSD": - @defaultinit = "/etc/rc.d" - else - @defaultinit = "/etc/init.d" - @defaultrc = "/etc/rc%s.d" - end - end -# # Make sure we've got a search path set up. If they don't -# # specify one, try to determine one. -# def configchk -# unless defined? @searchpaths -# Puppet.notice "Initting search paths" -# @searchpaths = [] -# end -# unless @searchpaths.length > 0 -# if init = self.defaultinit -# self.notice "Adding default init" -# @searchpaths << init -# else -# self.notice "No default init for %s" % -# Facter["operatingsystem"].value -# -# raise Puppet::Error.new( -# "You must specify a valid search path for service %s" % -# self.name -# ) -# end -# end -# end -# -# # Get the default init path. -# def defaultinit -# unless defined? @defaultinit -# case Facter["operatingsystem"].value -# when "FreeBSD": -# @defaultinit = "/etc/rc.d" -# else -# @defaultinit = "/etc/init.d" -# @defaultrc = "/etc/rc%s.d" -# end -# end -# -# return @defaultinit -# end - - # Mark that our init script supports 'status' commands. - def hasstatus=(value) - case value - when true, "true": @parameters[:hasstatus] = true - when false, "false": @parameters[:hasstatus] = false - else - raise Puppet::Error, "Invalid 'hasstatus' value %s" % - value.inspect - end - end +module Puppet + module ServiceTypes + module InitSvc + # Make sure we've got a search path set up. If they don't + # specify one, try to determine one. + def configchk + unless defined? @searchpaths + @searchpaths = [] + end + unless @searchpaths.length > 0 + if init = self.defaultinit + self.notice "Adding default init" + @searchpaths << init + else + self.notice "No default init for %s" % + Facter["operatingsystem"].value + + raise Puppet::Error.new( + "You must specify a valid search path for service %s" % + self.name + ) + end + end + end - # it'd be nice if i didn't throw the output away... - # this command returns true if the exit code is 0, and returns - # false otherwise - def initcmd(cmd) - script = self.initscript + # Get the default init path. + def defaultinit + unless defined? @defaultinit + case Facter["operatingsystem"].value + when "FreeBSD": + @defaultinit = "/etc/rc.d" + else + @defaultinit = "/etc/init.d" + @defaultrc = "/etc/rc%s.d" + end + end + + return @defaultinit + end - self.debug "Executing '%s %s' as initcmd for '%s'" % - [script,cmd,self] + # Mark that our init script supports 'status' commands. + def hasstatus=(value) + case value + when true, "true": @parameters[:hasstatus] = true + when false, "false": @parameters[:hasstatus] = false + else + raise Puppet::Error, "Invalid 'hasstatus' value %s" % + value.inspect + end + end - rvalue = Kernel.system("%s %s" % - [script,cmd]) + # it'd be nice if i didn't throw the output away... + # this command returns true if the exit code is 0, and returns + # false otherwise + def initcmd(cmd) + script = self.initscript - self.debug "'%s' ran with exit status '%s'" % - [cmd,rvalue] + self.debug "Executing '%s %s' as initcmd for '%s'" % + [script,cmd,self] + rvalue = Kernel.system("%s %s" % + [script,cmd]) - rvalue - end + self.debug "'%s' ran with exit status '%s'" % + [cmd,rvalue] - # Where is our init script? - def initscript - if defined? @initscript - return @initscript - else - @initscript = self.search(self.name) - end - end - # Enable a service, so it's started at boot time. This basically - # just creates links in the RC directories, which means that, well, - # we need to know where the rc directories are. - # FIXME This should probably be a state or something, and - # it should actually create use Symlink objects... - # At this point, people should just link objects for enabling, - # if they're running on a system that doesn't have a tool to - # manage init script links. - #def enable - #end - - #def disable - #end - - def search(name) - self[:path].each { |path| - fqname = File.join(path,name) - begin - stat = File.stat(fqname) - rescue - # should probably rescue specific errors... - self.debug("Could not find %s in %s" % [name,path]) - next + rvalue end - # if we've gotten this far, we found a valid script - return fqname - } - raise Puppet::Error, "Could not find init script for '%s'" % name - end + # Where is our init script? + def initscript + if defined? @initscript + return @initscript + else + @initscript = self.search(self.name) + end + end - # The start command is just the init scriptwith 'start'. - def startcmd - self.initscript + " start" - end + # Store the search path for init scripts. This will generally not + # be called. + def parampath=(ary) + unless ary.is_a?(Array) + ary = [ary] + end + @parameters[:path] = ary + @searchpaths = ary.find_all { |dir| + File.directory?(dir) + } + end - # If it was specified that the init script has a 'status' command, then - # we just return that; otherwise, we return false, which causes it to - # fallback to other mechanisms. - def statuscmd - if self[:hasstatus] - return self.initscript + " status" - else - return false - end - end + # Enable a service, so it's started at boot time. This basically + # just creates links in the RC directories, which means that, well, + # we need to know where the rc directories are. + # FIXME This should probably be a state or something, and + # it should actually create use Symlink objects... + # At this point, people should just link objects for enabling, + # if they're running on a system that doesn't have a tool to + # manage init script links. + #def enable + #end + + #def disable + #end + + def search(name) + @searchpaths.each { |path| + fqname = File.join(path,name) + begin + stat = File.stat(fqname) + rescue + # should probably rescue specific errors... + self.debug("Could not find %s in %s" % [name,path]) + next + end + + # if we've gotten this far, we found a valid script + return fqname + } + raise Puppet::Error, "Could not find init script for '%s'" % name + end + + # The start command is just the init scriptwith 'start'. + def startcmd + self.initscript + " start" + end + + # If it was specified that the init script has a 'status' command, then + # we just return that; otherwise, we return false, which causes it to + # fallback to other mechanisms. + def statuscmd + if self[:hasstatus] + return self.initscript + " status" + else + return false + end + end - # The stop command is just the init script with 'stop'. - def stopcmd - self.initscript + " stop" + # The stop command is just the init script with 'stop'. + def stopcmd + self.initscript + " stop" + end + end end end - -# $Id$ diff --git a/lib/puppet/type/service/smf.rb b/lib/puppet/type/service/smf.rb index f16eb422a..9f59c9d53 100755 --- a/lib/puppet/type/service/smf.rb +++ b/lib/puppet/type/service/smf.rb @@ -1,29 +1,29 @@ -# Solaris 10 SMF-style services. This is not yet implemented, which is probably -# somewhat obvious. -Puppet.type(:service).newsvctype(:smf) do - def restartcmd - end +module Puppet + module ServiceTypes + module SMFSvc + def restartcmd + end - # The start command is just the init scriptwith 'start'. - def startcmd - self.initscript + " start" - end + # The start command is just the init scriptwith 'start'. + def startcmd + self.initscript + " start" + end - # If it was specified that the init script has a 'status' command, then - # we just return that; otherwise, we return false, which causes it to - # fallback to other mechanisms. - def statuscmd - if self[:hasstatus] - return self.initscript + " status" - else - return false - end - end + # If it was specified that the init script has a 'status' command, then + # we just return that; otherwise, we return false, which causes it to + # fallback to other mechanisms. + def statuscmd + if self[:hasstatus] + return self.initscript + " status" + else + return false + end + end - # The stop command is just the init script with 'stop'. - def stopcmd - self.initscript + " stop" + # The stop command is just the init script with 'stop'. + def stopcmd + self.initscript + " stop" + end + end end end - -# $Id$ diff --git a/lib/puppet/type/state.rb b/lib/puppet/type/state.rb index e1e1b77b8..fdc54ffcc 100644 --- a/lib/puppet/type/state.rb +++ b/lib/puppet/type/state.rb @@ -7,7 +7,7 @@ require 'puppet/statechange' module Puppet class State < Puppet::Element - attr_accessor :is + 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 @@ -19,19 +19,10 @@ class State < Puppet::Element class << self attr_accessor :unmanaged attr_reader :name - - def inspect - "State(%s)" % self.name - end - - def to_s - self.inspect - end end - + # initialize our state def initialize(hash) - super() @is = nil unless hash.include?(:parent) @@ -48,21 +39,6 @@ class State < Puppet::Element end end - def inspect - str = "State('%s', " % self.name - if defined? @is and @is - str += "@is = '%s', " % @is - else - str += "@is = nil, " - end - - if defined? @should and @should - str += "@should = '%s')" % @should.join(", ") - else - str += "@should = nil)" - 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 @@ -136,6 +112,7 @@ class State < Puppet::Element def should if defined? @should unless @should.is_a?(Array) + self.warning @should.inspect raise Puppet::DevError, "should for %s on %s is not an array" % [self.class.name, @parent.name] end @@ -153,20 +130,16 @@ class State < Puppet::Element @shouldorig = values - if self.respond_to?(:validate) - values.each { |val| - validate(val) - } - end - if self.respond_to?(:munge) + if self.respond_to?(:shouldprocess) @should = values.collect { |val| - self.munge(val) + self.shouldprocess(val) } else @should = values end end + # How should a state change be printed as a string? def change_to_s begin diff --git a/lib/puppet/type/symlink.rb b/lib/puppet/type/symlink.rb index 2be33cb1d..c1ac27b8b 100755 --- a/lib/puppet/type/symlink.rb +++ b/lib/puppet/type/symlink.rb @@ -1,11 +1,13 @@ + require 'etc' require 'puppet/type/state' require 'puppet/type/pfile' module Puppet - newtype(:symlink) do - @doc = "Create symbolic links to existing files." - newstate(:target) do + # okay, how do we deal with parameters that don't have operations + # associated with them? + class State + class SymlinkTarget < Puppet::State require 'etc' attr_accessor :file @@ -83,26 +85,46 @@ module Puppet #self.parent.newevent(:event => :inode_changed) end end - - attr_reader :stat, :path, :params - - copyparam(Puppet.type(:file), :path) - - newparam(:recurse) do - desc "If target is a directory, recursively create + end + + class Type + class Symlink < Type + attr_reader :stat, :path, :params + # class instance variable + @states = [ + Puppet::State::SymlinkTarget + ] + + @parameters = [ + :path, + :recurse + ] + + @paramdoc[:path] = "Path of link to create." + @paramdoc[:recurse] = "If target is a directory, recursively create directories (using `file`'s `source` parameter) and link all contained files." + @doc = "Create symbolic links to existing files." + @name = :symlink + @namevar = :path + + def initialize(hash) + @arghash = self.argclean(hash.dup) + @arghash.delete(self.class.namevar) - munge do |value| + super + end + + def paramrecurse=(value) @stat = nil - @target = @parent.state(:target).should + @target = self.state(:target).should # we want to remove our state, because we're creating children # to do the links if FileTest.exist?(@target) @stat = File.stat(@target) else - @parent.info "Target %s must exist for recursive links" % + self.info "Target %s must exist for recursive links" % @target return end @@ -113,7 +135,7 @@ module Puppet return end - @parent.delete(:target) + self.delete(:target) recurse = value # we might have a string, rather than a number @@ -136,25 +158,25 @@ module Puppet # working in pfile args = { - :name => @parent.name, + :name => self.name, :linkmaker => true, :recurse => recurse, :source => @target } - dir = Puppet.type(:file).implicitcreate(args) - dir.parent = @parent - @parent.debug "Got dir %s" % dir.name - @parent.push dir + dir = Puppet::Type::PFile.implicitcreate(args) + dir.parent = self + self.debug "Got dir %s" % dir.name + self.push dir + #Dir.foreach(@target) { |file| + # next if file =~ /^\.\.?$/ # skip . and .. + # newtarget = File.join(@target,file) + # #stat = File.stat(File.join(@target,file)) + # self.newchild(file, :target => newtarget) + #} end - end - - def initialize(hash) - @arghash = self.argclean(hash.dup) - @arghash.delete(self.class.namevar) - super - end - end # Puppet.type(:symlink) + end # Puppet::Type::Symlink + end # Puppet::Type end # $Id$ diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index 59d51e680..f91eaa754 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -4,87 +4,10 @@ require 'puppet/type/state' require 'puppet/type/pfile' module Puppet - newtype(:tidy, Puppet.type(:file)) do - @doc = "Remove unwanted files based on specific criteria." - - newparam(:path) do - desc "The path to the file to manage. Must be fully qualified." - isnamevar - end - - copyparam(Puppet.type(:file), :backup) - - newparam(:age) do - desc "Tidy files whose age is equal to or greater than - the specified number of days." - - munge do |age| - case age - when /^[0-9]+$/, /^[0-9]+[dD]/: - Integer(age.gsub(/[^0-9]+/,'')) * - 60 * 60 * 24 - when /^[0-9]+$/, /^[0-9]+[hH]/: - Integer(age.gsub(/[^0-9]+/,'')) * 60 * 60 - when /^[0-9]+[mM]/: - Integer(age.gsub(/[^0-9]+/,'')) * 60 - when /^[0-9]+[sS]/: - Integer(age.gsub(/[^0-9]+/,'')) - else - raise Puppet::Error.new("Invalid tidy age %s" % age) - end - end - end - - newparam(:size) do - desc "Tidy files whose size is equal to or greater than - the specified size. Unqualified values are in kilobytes, but - *b*, *k*, and *m* can be appended to specify *bytes*, *kilobytes*, - and *megabytes*, respectively. Only the first character is - significant, so the full word can also be used." - - munge do |size| - if FileTest.directory?(@parent[:path]) - # don't do size comparisons for directories - return - end - case size - when /^[0-9]+$/, /^[0-9]+[kK]/: - Integer(size.gsub(/[^0-9]+/,'')) * 1024 - when /^[0-9]+[bB]/: - Integer(size.gsub(/[^0-9]+/,'')) - when /^[0-9]+[mM]/: - Integer(size.gsub(/[^0-9]+/,'')) * - 1024 * 1024 - else - raise Puppet::Error.new("Invalid tidy size %s" % size) - end - end - end - - newparam(:type) do - desc "Set the mechanism for determining age. Access - time is the default mechanism, but modification." - - munge do |type| - case type - when "atime", "mtime", "ctime": - @parameters[:type] = type.intern - else - raise Puppet::Error.new("Invalid tidy type %s" % type) - end - end - end - - newparam(:recurse) do - desc "If target is a directory, recursively descend - into the directory looking for files to tidy." - end - - newparam(:rmdirs) do - desc "Tidy directories in addition to files." - end - - newstate(:tidyup) do + # okay, how do we deal with parameters that don't have operations + # associated with them? + class State + class TidyUp < Puppet::State require 'etc' @nodoc = true @@ -150,30 +73,110 @@ module Puppet return :file_tidied end end + end + + class Type + class Tidy < PFile + + # class instance variable + @states = [ + Puppet::State::TidyUp + ] + + @parameters = [ + :path, + :age, + :size, + :type, + :backup, + :rmdirs, + :recurse + ] + + @paramdoc[:age] = "Tidy files whose age is equal to or greater than + the specified number of days." + @paramdoc[:size] = "Tidy files whose size is equal to or greater than + the specified size. Unqualified values are in kilobytes, but + *b*, *k*, and *m* can be appended to specify *bytes*, *kilobytes*, + and *megabytes*, respectively. Only the first character is + significant, so the full word can also be used." + @paramdoc[:type] = "Set the mechanism for determining age. Access + time is the default mechanism, but modification." + @paramdoc[:recurse] = "If target is a directory, recursively descend + into the directory looking for files to tidy." + @paramdoc[:rmdirs] = "Tidy directories in addition to files." + @doc = "Remove unwanted files based on specific criteria." + @name = :tidy + @namevar = :path + + @depthfirst = true + + def initialize(hash) + super - @depthfirst = true + unless @parameters.include?(:age) or + @parameters.include?(:size) + unless FileTest.directory?(self[:path]) + # don't do size comparisons for directories + raise Puppet::Error, "Tidy must specify size, age, or both" + end + end - def initialize(hash) - super + # only allow backing up into filebuckets + unless self[:backup].is_a? Puppet::Client::Dipper + self[:backup] = false + end + self[:tidyup] = [:age, :size].collect { |param| + @parameters[param] + }.reject { |p| p == false } + end - unless @parameters.include?(:age) or - @parameters.include?(:size) - unless FileTest.directory?(self[:path]) + def paramage=(age) + @parameters[:age] = age + case age + when /^[0-9]+$/, /^[0-9]+[dD]/: + @parameters[:age] = Integer(age.gsub(/[^0-9]+/,'')) * + 60 * 60 * 24 + when /^[0-9]+$/, /^[0-9]+[hH]/: + @parameters[:age] = Integer(age.gsub(/[^0-9]+/,'')) * 60 * 60 + when /^[0-9]+[mM]/: + @parameters[:age] = Integer(age.gsub(/[^0-9]+/,'')) * 60 + when /^[0-9]+[sS]/: + @parameters[:age] = Integer(age.gsub(/[^0-9]+/,'')) + else + raise Puppet::Error.new("Invalid tidy age %s" % age) + end + end + + def paramsize=(size) + if FileTest.directory?(self[:path]) # don't do size comparisons for directories - raise Puppet::Error, "Tidy must specify size, age, or both" + return + end + case size + when /^[0-9]+$/, /^[0-9]+[kK]/: + @parameters[:size] = Integer(size.gsub(/[^0-9]+/,'')) * 1024 + when /^[0-9]+[bB]/: + @parameters[:size] = Integer(size.gsub(/[^0-9]+/,'')) + when /^[0-9]+[mM]/: + @parameters[:size] = Integer(size.gsub(/[^0-9]+/,'')) * + 1024 * 1024 + else + raise Puppet::Error.new("Invalid tidy size %s" % size) end end - # only allow backing up into filebuckets - unless self[:backup].is_a? Puppet::Client::Dipper - self[:backup] = false + def paramtype=(type) + case type + when "atime", "mtime", "ctime": + @parameters[:type] = type.intern + else + raise Puppet::Error.new("Invalid tidy type %s" % type) + end end - self[:tidyup] = [:age, :size].collect { |param| - @parameters[param] - }.reject { |p| p == false } - end - end + end # Puppet::Type::Symlink + end # Puppet::Type end # $Id$ diff --git a/lib/puppet/type/typegen/filerecord.rb b/lib/puppet/type/typegen/filerecord.rb index 537523463..6e502c170 100644 --- a/lib/puppet/type/typegen/filerecord.rb +++ b/lib/puppet/type/typegen/filerecord.rb @@ -5,7 +5,7 @@ require 'etc' require 'puppet/type' require 'puppet/type/typegen' -class Puppet.type(:filerecord) < Puppet::Type::TypeGenerator +class Puppet::Type::FileRecord < Puppet::Type::TypeGenerator class << self # The name of the record type. Probably superfluous. attr_accessor :name @@ -131,7 +131,7 @@ class Puppet.type(:filerecord) < Puppet::Type::TypeGenerator end def initialize(hash) - if self.class == Puppet.type(:filerecord) + if self.class == Puppet::Type::FileRecord self.class.newtype(hash) return end diff --git a/lib/puppet/type/typegen/filetype.rb b/lib/puppet/type/typegen/filetype.rb index 9fc6b41f0..c7ed89b25 100644 --- a/lib/puppet/type/typegen/filetype.rb +++ b/lib/puppet/type/typegen/filetype.rb @@ -3,7 +3,7 @@ require 'puppet/type' require 'puppet/type/typegen' -class Puppet.type(:filetype) < Puppet::Type::TypeGenerator +class Puppet::Type::FileType < Puppet::Type::TypeGenerator @parameters = [:name, :recordsep, :escapednewlines] @namevar = :name @@ -32,11 +32,11 @@ class Puppet.type(:filetype) < Puppet::Type::TypeGenerator # Add a new record to our filetype. This should never be called on the FileType # class itself, only on its subclasses. def FileType.addrecord(hash = {}) - if self == Puppet.type(:filerecord) + if self == Puppet::Type::FileRecord raise Puppet::DevError, "Cannot add records to the FileType base class" end - newrecord = Puppet.type(:filerecord).newtype(hash) + newrecord = Puppet::Type::FileRecord.newtype(hash) newrecord.filetype = self if block_given? @@ -186,7 +186,7 @@ class Puppet.type(:filetype) < Puppet::Type::TypeGenerator # if we are the FileType object itself, we create a new type # otherwise, we create an instance of an existing type # yes, this should be more straightforward - if self.class == Puppet.type(:filetype) + if self.class == Puppet::Type::FileType self.class.newtype(hash) return end diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index fddf64a85..183b6bb98 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -4,24 +4,19 @@ require 'puppet/type/state' require 'puppet/type/nameservice' module Puppet - newtype(:user, Puppet::Type::NSSType) do - case Facter["operatingsystem"].value - when "Darwin": - @parentstate = Puppet::NameService::NetInfo::NetInfoState - @parentmodule = Puppet::NameService::NetInfo - else - @parentstate = Puppet::NameService::ObjectAdd::ObjectAddUser - @parentmodule = Puppet::NameService::ObjectAdd - end - - newstate(:uid, @parentstate) do - desc "The user ID. Must be specified numerically. For new users + class State + module UserUID + def self.doc + "The user ID. Must be specified numerically. For new users being created, if no user ID is specified then one will be chosen automatically, which will likely result in the same user having different IDs on different systems, which is not recommended." + end - isautogen + def self.name + :uid + end def autogen highest = 0 @@ -36,7 +31,7 @@ module Puppet return highest + 1 end - munge do |value| + def shouldprocess(value) case value when String if value =~ /^[-0-9]+$/ @@ -56,13 +51,17 @@ module Puppet end end - newstate(:gid, @parentstate) do - desc "The user's primary group. Can be specified numerically or + module UserGID + def self.doc + "The user's primary group. Can be specified numerically or by name." + end - isautogen + def self.name + :gid + end - munge do |gid| + def shouldprocess(gid) method = :getgrgid case gid when String @@ -94,121 +93,195 @@ module Puppet end end - newstate(:comment, @parentstate) do - desc "A description of the user. Generally is a user's full name." + module UserComment + def self.doc + "A description of the user. Generally is a user's full name." + end - isoptional + def self.name + :comment + end + + def self.optional? + true + end - @posixmethod = :gecos + def self.posixmethod + :gecos + end end - newstate(:home, @parentstate) do - desc "The home directory of the user. The directory must be created + module UserHome + def self.doc + "The home directory of the user. The directory must be created separately and is not currently checked for existence." + end - isautogen - @posixmethod = :dir + def self.name + :home + end + + def self.posixmethod + :dir + end end - newstate(:shell, @parentstate) do - desc "The user's login shell. The shell must exist and be + module UserShell + def self.doc + "The user's login shell. The shell must exist and be executable." - isautogen + end + + def self.name + :shell + end end # these three states are all implemented differently on each platform, # so i'm disabling them for now # FIXME Puppet::State::UserLocked is currently non-functional - #newstate(:locked, @parentstate) do - # desc "The expected return code. An error will be returned if the - # executed command returns something else." - #end + module UserLocked + def self.doc + "The expected return code. An error will be returned if the + executed command returns something else." + end + + def self.name + :locked + end + end # FIXME Puppet::State::UserExpire is currently non-functional - #newstate(:expire, @parentstate) do - # desc "The expected return code. An error will be returned if the - # executed command returns something else." - # @objectaddflag = "-e" - # isautogen - #end + module UserExpire + def self.doc + "The expected return code. An error will be returned if the + executed command returns something else." + end + + def self.name; :expire; end + end # FIXME Puppet::State::UserInactive is currently non-functional - #newstate(:inactive, @parentstate) do - # desc "The expected return code. An error will be returned if the - # executed command returns something else." - # @objectaddflag = "-f" - # isautogen - #end - - newparam(:name) do - desc "User name. While limitations are determined for - each operating system, it is generally a good idea to keep to - the degenerate 8 characters, beginning with a letter." - isnamevar + module UserInactive + def self.doc + "The expected return code. An error will be returned if the + executed command returns something else." + end + + def self.name; :inactive; end end - @doc = "Manage users. Currently can create and modify users, but - cannot delete them. Theoretically all of the parameters are - optional, but if no parameters are specified the comment will - be set to the user name in order to make the internals work out - correctly." + end - @netinfodir = "users" + class Type + class User < Type + statenames = [ + "UserUID", + "UserGID", + "UserComment", + "UserHome", + "UserShell" + ] + @statemodule = nil + case Facter["operatingsystem"].value + when "Darwin": + @statemodule = Puppet::NameService::NetInfo + else + @statemodule = Puppet::NameService::ObjectAdd + end - def exists? - self.class.parentmodule.exists?(self) - end + class << self + attr_accessor :netinfodir + attr_accessor :statemodule + end - def getinfo(refresh = false) - if @userinfo.nil? or refresh == true + @states = [] + + @states = statenames.collect { |name| + fullname = @statemodule.to_s + "::" + name begin - @userinfo = Etc.getpwnam(self[:name]) - rescue ArgumentError => detail - @userinfo = nil + eval(fullname) + rescue NameError + raise Puppet::DevError, "Could not retrieve state class %s" % + fullname end + }.each { |klass| + klass.complete + } + + @parameters = [ + :name + ] + + @paramdoc[:name] = "User name. While limitations are determined for + each operating system, it is generally a good idea to keep to the + degenerate 8 characters, beginning with a letter." + + @doc = "Manage users. Currently can create and modify users, but + cannot delete them. Theoretically all of the parameters are + optional, but if no parameters are specified the comment will + be set to the user name in order to make the internals work out + correctly." + @name = :user + @namevar = :name + + @netinfodir = "users" + + def exists? + self.class.statemodule.exists?(self) end - @userinfo - end + def getinfo(refresh = false) + if @userinfo.nil? or refresh == true + begin + @userinfo = Etc.getpwnam(self[:name]) + rescue ArgumentError => detail + @userinfo = nil + end + end - def initialize(hash) - @userinfo = nil - super - - # Verify that they have provided everything necessary, if we - # are trying to manage the user - if self.managed? - self.class.states.each { |state| - next if @states.include?(state.name) - - unless state.autogen? or state.optional? - if state.method_defined?(:autogen) - self[state.name] = :auto - else - raise Puppet::Error, - "Users require a value for %s" % state.name + @userinfo + end + + def initialize(hash) + @userinfo = nil + super + + # Verify that they have provided everything necessary, if we + # are trying to manage the user + if self.managed? + self.class.states.each { |state| + next if @states.include?(state.name) + + unless state.autogen? or state.optional? + if state.method_defined?(:autogen) + self[state.name] = :auto + else + raise Puppet::Error, + "Users require a value for %s" % state.name + end end - end - } + } - if @states.empty? - self[:comment] = self[:name] + if @states.empty? + self[:comment] = self[:name] + end end end - end - - def retrieve - info = self.getinfo(true) - if info.nil? - # the user does not exist - @states.each { |name, state| - state.is = :notfound - } - return - else - super + def retrieve + info = self.getinfo(true) + + if info.nil? + # the user does not exist + @states.each { |name, state| + state.is = :notfound + } + return + else + super + end end end end diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index 2418cad25..d1878f592 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -19,8 +19,8 @@ module Util if group.is_a?(Integer) gid = group else - unless obj = Puppet.type(:group)[group] - obj = Puppet.type(:group).create( + unless obj = Puppet::Type::Group[group] + obj = Puppet::Type::Group.create( :name => group, :check => [:gid] ) @@ -47,8 +47,8 @@ module Util if user.is_a?(Integer) uid = user else - unless obj = Puppet.type(:user)[user] - obj = Puppet.type(:user).create( + unless obj = Puppet::Type::User[user] + obj = Puppet::Type::User.create( :name => user, :check => [:uid, :gid] ) @@ -114,12 +114,12 @@ module Util if useself Puppet::Log.create( :level => level, - :source => self, :message => args ) else Puppet::Log.create( :level => level, + :source => self, :message => args ) end diff --git a/test/executables/puppetbin.rb b/test/executables/puppetbin.rb index f16ccbbf2..d075d8431 100755 --- a/test/executables/puppetbin.rb +++ b/test/executables/puppetbin.rb @@ -35,9 +35,7 @@ class TestPuppetBin < Test::Unit::TestCase output = nil cmd = "puppet" - if Puppet[:debug] - cmd += " --debug" - end + cmd += " --verbose" #cmd += " --fqdn %s" % fqdn cmd += " --confdir %s" % Puppet[:puppetconf] cmd += " --vardir %s" % Puppet[:puppetvar] diff --git a/test/executables/puppetmodule.rb b/test/executables/puppetmodule.rb index 429e29e36..2e97a963a 100755 --- a/test/executables/puppetmodule.rb +++ b/test/executables/puppetmodule.rb @@ -19,15 +19,11 @@ libdirs = $:.find_all { |dir| } ENV["RUBYLIB"] = libdirs.join(":") -$module = File.join($puppetbase, "ext", "module_puppet") +$module = File.join($puppetbase, "ext", "module:puppet") class TestPuppetModule < Test::Unit::TestCase include ServerTest - def test_existence - assert(FileTest.exists?($module), "Module does not exist") - end - def test_execution file = tempfile() @@ -45,7 +41,6 @@ class TestPuppetModule < Test::Unit::TestCase cmd += " --vardir %s" % Puppet[:puppetvar] if Puppet[:debug] cmd += " --logdest %s" % "console" - cmd += " --debug" else cmd += " --logdest %s" % "/dev/null" end diff --git a/test/language/snippets.rb b/test/language/snippets.rb index a213d554f..f7cf21548 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -159,7 +159,7 @@ class TestSnippets < Test::Unit::TestCase %w{a b c d}.each { |letter| file = "/tmp/create%stest" % letter Puppet.info "testing %s" % file - assert(Puppet.type(:file)[file], "File %s does not exist" % file) + assert(Puppet::Type::PFile[file], "File %s does not exist" % file) assert(FileTest.exists?(file)) @@tmpfiles << file } @@ -217,7 +217,7 @@ class TestSnippets < Test::Unit::TestCase obj = nil assert_nothing_raised { - obj = Puppet.type(:file)[file] + obj = Puppet::Type::PFile[file] } assert_nothing_raised { diff --git a/test/other/events.rb b/test/other/events.rb index 911180b28..f295608f1 100755 --- a/test/other/events.rb +++ b/test/other/events.rb @@ -19,11 +19,11 @@ class TestEvents < Test::Unit::TestCase def test_simplesubscribe name = tempfile() - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => name, :create => true ) - exec = Puppet.type(:exec).create( + exec = Puppet::Type::Exec.create( :name => "echo true", :path => "/usr/bin:/bin", :refreshonly => true, @@ -32,18 +32,18 @@ class TestEvents < Test::Unit::TestCase comp = newcomp("eventtesting", file, exec) - trans = assert_events([:file_created], comp) + trans = assert_events(comp, [:file_created], "events") assert_equal(1, trans.triggered?(exec, :refresh)) end def test_simplerequire name = tempfile() - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => name, :create => true ) - exec = Puppet.type(:exec).create( + exec = Puppet::Type::Exec.create( :name => "echo true", :path => "/usr/bin:/bin", :refreshonly => true, @@ -51,7 +51,7 @@ class TestEvents < Test::Unit::TestCase ) - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "eventtesting" ) comp.push exec @@ -74,13 +74,13 @@ class TestEvents < Test::Unit::TestCase case l when :a name = tempfile() + l.to_s - objects[l] = Puppet.type(:file).create( + objects[l] = Puppet::Type::PFile.create( :name => name, :create => true ) @@tmpfiles << name when :b - objects[l] = Puppet.type(:exec).create( + objects[l] = Puppet::Type::Exec.create( :name => "touch %s" % fname, :path => "/usr/bin:/bin", :refreshonly => true @@ -89,7 +89,7 @@ class TestEvents < Test::Unit::TestCase end - comps[l] = Puppet.type(:component).create( + comps[l] = Puppet::Type::Component.create( :name => "eventtesting%s" % l ) diff --git a/test/other/log.rb b/test/other/log.rb index 0bc2656ea..f082be6ad 100644 --- a/test/other/log.rb +++ b/test/other/log.rb @@ -44,8 +44,6 @@ class TestLog < Test::Unit::TestCase def test_logfile fact = nil levels = nil - oldlevel = Puppet[:loglevel] - Puppet[:loglevel] = :debug levels = getlevels logfile = tempfile() assert_nothing_raised() { @@ -61,7 +59,6 @@ class TestLog < Test::Unit::TestCase } } assert(count == levels.length) - Puppet[:loglevel] = oldlevel end def test_syslog @@ -103,14 +100,12 @@ class TestLog < Test::Unit::TestCase end def test_output - olddebug = Puppet[:debug] Puppet[:debug] = false assert(Puppet.err("This is an error").is_a?(Puppet::Log)) assert(Puppet.debug("This is debugging").nil?) Puppet[:debug] = true assert(Puppet.err("This is an error").is_a?(Puppet::Log)) assert(Puppet.debug("This is debugging").is_a?(Puppet::Log)) - Puppet[:debug] = olddebug end def test_creatingdirs @@ -126,7 +121,7 @@ class TestLog < Test::Unit::TestCase path = tempfile File.open(path, "w") { |f| f.puts "yayness" } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => path, :check => [:owner, :group, :mode, :checksum] ) @@ -162,7 +157,7 @@ class TestLog < Test::Unit::TestCase # Verify that the error and source are always strings def test_argsAreStrings msg = nil - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tempfile(), :check => %w{owner group} ) @@ -180,7 +175,7 @@ class TestLog < Test::Unit::TestCase # Verify that loglevel behaves as one expects def test_loglevel path = tempfile() - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => path, :create => true ) diff --git a/test/other/metrics.rb b/test/other/metrics.rb index 36a12eb1f..dbae3cf54 100644 --- a/test/other/metrics.rb +++ b/test/other/metrics.rb @@ -25,7 +25,7 @@ if $haverrd eventmax = 10 maxdiff = 10 - types = [Puppet.type(:file), Puppet.type(:package), Puppet.type(:package)] + types = [Puppet::Type::PFile, Puppet::Type::Package, Puppet::Type::Service] data = [:total, :managed, :outofsync, :changed, :totalchanges] events = [:file_changed, :package_installed, :service_started] diff --git a/test/other/overrides.rb b/test/other/overrides.rb index d9220264e..be9ccd2ce 100755 --- a/test/other/overrides.rb +++ b/test/other/overrides.rb @@ -29,7 +29,7 @@ class TestOverrides < Test::Unit::TestCase baseobj = nil basefile = File.join(basedir, "file") assert_nothing_raised("Could not create base obj") { - baseobj = Puppet.type(:file).create( + baseobj = Puppet::Type::PFile.create( :path => basedir, :recurse => true, :mode => "755" @@ -40,7 +40,7 @@ class TestOverrides < Test::Unit::TestCase subdir = File.join(basedir, "0") subfile = File.join(subdir, "file") assert_nothing_raised("Could not create sub obj") { - subobj = Puppet.type(:file).create( + subobj = Puppet::Type::PFile.create( :path => subdir, :recurse => true, :mode => "644" @@ -63,7 +63,7 @@ class TestOverrides < Test::Unit::TestCase baseobj = nil assert_nothing_raised("Could not create base obj") { - baseobj = Puppet.type(:file).create( + baseobj = Puppet::Type::PFile.create( :path => basedir, :recurse => true, :mode => "755" @@ -87,7 +87,7 @@ class TestOverrides < Test::Unit::TestCase end assert_nothing_raised("Could not create sub obj") { - children << Puppet.type(:file).create( + children << Puppet::Type::PFile.create( :path => subdir, :recurse => true, :mode => mode diff --git a/test/other/relationships.rb b/test/other/relationships.rb index f2764c639..04cbd73dc 100755 --- a/test/other/relationships.rb +++ b/test/other/relationships.rb @@ -12,7 +12,7 @@ class TestRelationships < Test::Unit::TestCase include TestPuppet def newfile assert_nothing_raised() { - return Puppet.type(:file).create( + return Puppet::Type::PFile.create( :path => tempfile, :check => [:mode, :owner, :group] ) diff --git a/test/other/state.rb b/test/other/state.rb index 15512f6fe..c53829311 100644 --- a/test/other/state.rb +++ b/test/other/state.rb @@ -48,7 +48,7 @@ class TestStorage < Test::Unit::TestCase file = nil state = nil assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => "/etc/passwd" ) } diff --git a/test/other/transactions.rb b/test/other/transactions.rb index 5a00fbe09..f1897e0e5 100644 --- a/test/other/transactions.rb +++ b/test/other/transactions.rb @@ -34,7 +34,10 @@ class TestTransactions < Test::Unit::TestCase end def teardown - stopservices + Puppet::Type::Service.each { |serv| + serv[:running] = false + serv.sync + } #print "\n\n" if Puppet[:debug] super end @@ -63,13 +66,13 @@ class TestTransactions < Test::Unit::TestCase @@tmpfiles.push tmpfile hash[:name] = tmpfile assert_nothing_raised() { - return Puppet.type(:file).create(hash) + return Puppet::Type::PFile.create(hash) } end def newservice assert_nothing_raised() { - return Puppet.type(:service).create( + return Puppet::Type::Service.create( :name => "sleeper", :type => "init", :path => File.join($puppetbase,"examples/root/etc/init.d"), @@ -81,7 +84,7 @@ class TestTransactions < Test::Unit::TestCase def newexec(file) assert_nothing_raised() { - return Puppet.type(:exec).create( + return Puppet::Type::Exec.create( :name => "touch %s" % file, :path => "/bin:/usr/bin:/sbin:/usr/sbin", :returns => 0 @@ -123,7 +126,7 @@ class TestTransactions < Test::Unit::TestCase file[:mode] = "755" } - trans = assert_events([:inode_changed, :inode_changed], component) + trans = assert_events(component, [:inode_changed, :inode_changed], "file") assert_rollback_events(trans, [:inode_changed, :inode_changed], "file") @@ -138,8 +141,7 @@ class TestTransactions < Test::Unit::TestCase end # start a service, and then roll the modification back - # Disabled, because it wasn't really worth the effort. - def disabled_test_servicetrans + def test_servicetrans transaction = nil service = newservice() @@ -148,13 +150,9 @@ class TestTransactions < Test::Unit::TestCase assert_nothing_raised() { service[:running] = 1 } - service.retrieve - assert(service.insync?, "Service did not start") - system("ps -ef | grep ruby") - trans = assert_events([:service_started], component) - service.retrieve + trans = assert_events(component, [:service_started], "file") - assert_rollback_events(trans, [:service_stopped], "service") + assert_rollback_events(trans, [:service_stopped], "file") end # test that services are correctly restarted and that work is done @@ -188,7 +186,8 @@ class TestTransactions < Test::Unit::TestCase file[:mode] = "755" } - trans = assert_events( [:inode_changed], component) + trans = assert_events(component, + [:inode_changed], "testboth") assert(FileTest.exists?(execfile), "Execfile does not exist") File.unlink(execfile) @@ -196,7 +195,8 @@ class TestTransactions < Test::Unit::TestCase file[:group] = @groups[1] } - trans = assert_events([:inode_changed], component) + trans = assert_events(component, + [:inode_changed], "testboth") assert(FileTest.exists?(execfile), "Execfile does not exist") end @@ -220,14 +220,15 @@ class TestTransactions < Test::Unit::TestCase ecomp[:subscribe] = [[fcomp.class.name,fcomp.name]] exec[:refreshonly] = true - trans = assert_events([], component) + trans = assert_events(component, [], "subscribe1") assert_nothing_raised() { file[:group] = @groups[1] file[:mode] = "755" } - trans = assert_events([:inode_changed, :inode_changed], component) + trans = assert_events(component, [:inode_changed, :inode_changed], + "subscribe2") end diff --git a/test/puppettest.rb b/test/puppettest.rb index 382bfbc56..0871b5c13 100644 --- a/test/puppettest.rb +++ b/test/puppettest.rb @@ -7,15 +7,12 @@ require 'puppet' require 'test/unit' module TestPuppet - def newcomp(*ary) - name = nil - if ary[0].is_a?(String) - name = ary.shift - else - name = ary[0].name + def newcomp(name,*ary) + if name.is_a?(Puppet::Type) + ary.unshift name + name = name.name end - - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => name ) ary.each { |item| comp.push item } @@ -81,7 +78,7 @@ module TestPuppet if stype = Puppet::Type.type(:service) stype.each { |service| service[:running] = false - service.evaluate + service.sync } end end @@ -106,9 +103,6 @@ module TestPuppet # reset all of the logs Puppet::Log.close - - # Just in case there are processes waiting to die... - Process.waitall end def tempfile @@ -142,7 +136,6 @@ module TestPuppet "/tmp" end - @tmpdir = File.join(@tmpdir, "puppettesting") unless File.exists?(@tmpdir) @@ -153,57 +146,18 @@ module TestPuppet @tmpdir end - def assert_rollback_events(events, trans, msg = nil) - run_events(:rollback, events, trans, msg) + def assert_rollback_events(trans, events, msg) + run_events(:rollback, trans, events, msg) end - def assert_events(events, *items) + def assert_events(comp, events, msg = nil) trans = nil - comp = nil - msg = nil - - unless events.is_a? Array - raise Puppet::DevError, "Incorrect call of assert_events" - end - if items[-1].is_a? String - msg = items.pop - end - - remove_comp = false - # They either passed a comp or a list of items. - if items[0].is_a? Puppet.type(:component) - comp = items.shift - else - comp = newcomp(items[0].name, *items) - remove_comp = true - end msg ||= comp.name assert_nothing_raised("Component %s failed" % [msg]) { trans = comp.evaluate } run_events(:evaluate, trans, events, msg) - - if remove_comp - Puppet.type(:component).delete(comp) - end - - return trans - end - - # A simpler method that just applies what we have. - def assert_apply(*objects) - comp = newcomp(*objects) - trans = nil - - assert_nothing_raised("Failed to create transaction") { - trans = comp.evaluate - } - - assert_nothing_raised("Failed to evaluate transaction") { - trans.evaluate - } - Puppet.type(:component).delete(comp) end def run_events(type, trans, events, msg) diff --git a/test/server/fileserver.rb b/test/server/fileserver.rb index d1cdd696b..98c0c4cb4 100755 --- a/test/server/fileserver.rb +++ b/test/server/fileserver.rb @@ -151,7 +151,7 @@ class TestFileServer < Test::Unit::TestCase } assert_nothing_raised { - file = Puppet.type(:file)[tmpfile] + file = Puppet::Type::PFile[tmpfile] } output = "/\tfile" diff --git a/test/server/logger.rb b/test/server/logger.rb index dfaf50438..6dc5dec48 100644 --- a/test/server/logger.rb +++ b/test/server/logger.rb @@ -13,12 +13,6 @@ require 'cgi' class TestLogger < Test::Unit::TestCase include ServerTest - def setup - super - #Puppet[:debug] = true - Puppet[:logdest] = :console - end - # Test the log driver manually def test_localaddlog logger = nil @@ -29,7 +23,7 @@ class TestLogger < Test::Unit::TestCase msg = nil assert_nothing_raised { msg = Puppet::Log.create( - :level => :warning, + :level => :info, :message => "This is a message" ) } @@ -49,7 +43,7 @@ class TestLogger < Test::Unit::TestCase msg = nil assert_nothing_raised { msg = Puppet::Log.create( - :level => :warning, + :level => :info, :message => "This is a remote message" ) } @@ -72,7 +66,7 @@ class TestLogger < Test::Unit::TestCase msg = nil assert_nothing_raised { msg = Puppet::Log.create( - :level => :warning, + :level => :info, :message => "This is a logclient message" ) } diff --git a/test/types/basic.rb b/test/types/basic.rb index edc6bc66d..8cc5e406c 100644 --- a/test/types/basic.rb +++ b/test/types/basic.rb @@ -22,7 +22,7 @@ class TestBasic < Test::Unit::TestCase Puppet[:loglevel] = :debug if __FILE__ == $0 assert_nothing_raised() { - @component = Puppet.type(:component).create( + @component = Puppet::Type::Component.create( :name => "yaytest", :type => "testing" ) @@ -31,14 +31,14 @@ class TestBasic < Test::Unit::TestCase assert_nothing_raised() { @filepath = tempfile() @@tmpfiles << @filepath - @configfile = Puppet.type(:file).create( + @configfile = Puppet::Type::PFile.create( :path => @filepath, :create => true, :checksum => "md5" ) } assert_nothing_raised() { - @sleeper = Puppet.type(:service).create( + @sleeper = Puppet::Type::Service.create( :name => "sleeper", :type => "init", :path => File.join($puppetbase,"examples/root/etc/init.d"), diff --git a/test/types/component.rb b/test/types/component.rb index b97695f9f..7243ed2fc 100755 --- a/test/types/component.rb +++ b/test/types/component.rb @@ -42,7 +42,7 @@ class TestComponent < Test::Unit::TestCase end name = tempfile() + num.to_s - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => name, :checksum => "md5" ) @@ -51,7 +51,7 @@ class TestComponent < Test::Unit::TestCase end def mkcomp - Puppet.type(:component).create(:name => "component_" + randnum(1000).to_s) + Puppet::Type::Component.create(:name => "component_" + randnum(1000).to_s) end def mkrandcomp(numfiles, numdivs) @@ -114,12 +114,12 @@ class TestComponent < Test::Unit::TestCase File.open(tmpfile, File::WRONLY|File::CREAT|File::TRUNC) { |of| of.puts rand(100) } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tmpfile, :checksum => "md5" ) assert_nothing_raised { - cmd = Puppet.type(:exec).create( + cmd = Puppet::Type::Exec.create( :command => "pwd", :path => "/usr/bin:/bin:/usr/sbin:/sbin", :subscribe => [[file.class.name,file.name]], @@ -129,7 +129,7 @@ class TestComponent < Test::Unit::TestCase order = nil assert_nothing_raised { - order = Puppet.type(:component).sort([file, cmd]) + order = Puppet::Type::Component.sort([file, cmd]) } [cmd, file].each { |obj| @@ -145,12 +145,12 @@ class TestComponent < Test::Unit::TestCase File.open(tmpfile, File::WRONLY|File::CREAT|File::TRUNC) { |of| of.puts rand(100) } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tmpfile, :checksum => "md5" ) assert_nothing_raised { - cmd = Puppet.type(:exec).create( + cmd = Puppet::Type::Exec.create( :command => "pwd", :path => "/usr/bin:/bin:/usr/sbin:/sbin", :subscribe => [[file.class.name,file.name]], @@ -158,7 +158,7 @@ class TestComponent < Test::Unit::TestCase ) } - comp = Puppet.type(:component).create(:name => "RefreshTest") + comp = Puppet::Type::Component.create(:name => "RefreshTest") [cmd, file].each { |obj| comp.push obj } @@ -183,12 +183,12 @@ class TestComponent < Test::Unit::TestCase File.open(tmpfile, File::WRONLY|File::CREAT|File::TRUNC) { |of| of.puts rand(100) } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tmpfile, :checksum => "md5" ) assert_nothing_raised { - cmd = Puppet.type(:exec).create( + cmd = Puppet::Type::Exec.create( :command => "pwd", :path => "/usr/bin:/bin:/usr/sbin:/sbin", :refreshonly => true @@ -224,12 +224,12 @@ class TestComponent < Test::Unit::TestCase File.open(tmpfile, File::WRONLY|File::CREAT|File::TRUNC) { |of| of.puts rand(100) } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tmpfile, :checksum => "md5" ) assert_nothing_raised { - cmd = Puppet.type(:exec).create( + cmd = Puppet::Type::Exec.create( :command => "pwd", :path => "/usr/bin:/bin:/usr/sbin:/sbin", :refreshonly => true @@ -238,7 +238,7 @@ class TestComponent < Test::Unit::TestCase ocmd = nil assert_nothing_raised { - ocmd = Puppet.type(:exec).create( + ocmd = Puppet::Type::Exec.create( :command => "echo true", :path => "/usr/bin:/bin:/usr/sbin:/sbin", :refreshonly => true diff --git a/test/types/cron.rb b/test/types/cron.rb index 3ff1dbd18..1a60eecd3 100755 --- a/test/types/cron.rb +++ b/test/types/cron.rb @@ -34,9 +34,8 @@ class TestCron < Test::Unit::TestCase unless defined? @me raise "Could not retrieve user name; 'id' did not work" end - # god i'm lazy - @crontype = Puppet.type(:cron) + @crontype = Puppet::Type::Cron # Here we just create a fake cron type that answers to all of the methods # but does not modify our actual system. @@ -75,7 +74,7 @@ class TestCron < Test::Unit::TestCase def cronback tab = nil assert_nothing_raised { - tab = Puppet.type(:cron).crontype.read(@me) + tab = Puppet::Type::Cron.crontype.read(@me) } if $? == 0 @@ -119,14 +118,14 @@ class TestCron < Test::Unit::TestCase name = cron.name comp = newcomp(name, cron) - trans = assert_events([:cron_created], comp) + trans = assert_events(comp, [:cron_created], name) cron.retrieve assert(cron.insync?) - trans = assert_events([], comp) + trans = assert_events(comp, [], name) cron[:command] = :notfound - trans = assert_events([:cron_deleted], comp) + trans = assert_events(comp, [:cron_deleted], name) # the cron should no longer exist, not even in the comp - trans = assert_events([], comp) + trans = assert_events(comp, [], name) assert(!comp.include?(cron), "Cron is still a member of comp, after being deleted") @@ -176,14 +175,15 @@ class TestCron < Test::Unit::TestCase :user => @me ) } - comp = newcomp(cron) - assert_events([:cron_created], comp) - + assert_nothing_raised { + cron.sync + } assert_nothing_raised { cron[:month] = "June" } + comp = newcomp(cron) - assert_events([:cron_changed], comp) + assert_events(comp, [:cron_changed], "did not change cron job") end # Test that a cron job with spaces at the end doesn't get rewritten @@ -201,8 +201,8 @@ class TestCron < Test::Unit::TestCase } comp = newcomp(cron) - assert_events([:cron_created], comp, "did not create cron job") - assert_events([], comp, "cron job got rewritten") + assert_events(comp, [:cron_created], "did not create cron job") + assert_events(comp, [], "cron job got rewritten") end # Test that comments are correctly retained @@ -247,15 +247,15 @@ class TestCron < Test::Unit::TestCase # Test adding a cron when there is currently no file. def test_mkcronwithnotab - Puppet.type(:cron).crontype.remove(@me) + Puppet::Type::Cron.crontype.remove(@me) cron = mkcron("testwithnotab") cyclecron(cron) end def test_mkcronwithtab - Puppet.type(:cron).crontype.remove(@me) - Puppet.type(:cron).crontype.write(@me, + Puppet::Type::Cron.crontype.remove(@me) + Puppet::Type::Cron.crontype.write(@me, "1 1 1 1 * date > %s/crontesting\n" % testdir() ) @@ -264,20 +264,20 @@ class TestCron < Test::Unit::TestCase end def test_makeandretrievecron - Puppet.type(:cron).crontype.remove(@me) + Puppet::Type::Cron.crontype.remove(@me) name = "storeandretrieve" cron = mkcron(name) comp = newcomp(name, cron) - trans = assert_events([:cron_created], comp, name) + trans = assert_events(comp, [:cron_created], name) cron = nil - Puppet.type(:cron).clear - Puppet.type(:cron).retrieve(@me) + Puppet::Type::Cron.clear + Puppet::Type::Cron.retrieve(@me) - assert(cron = Puppet.type(:cron)[name], "Could not retrieve named cron") - assert_instance_of(Puppet.type(:cron), cron) + assert(cron = Puppet::Type::Cron[name], "Could not retrieve named cron") + assert_instance_of(Puppet::Type::Cron, cron) end # Do input validation testing on all of the parameters. @@ -302,16 +302,14 @@ class TestCron < Test::Unit::TestCase }, :month => { :valid => [ 1, 11, 12, "mar", "March", "apr", "October", "DeCeMbEr" ], - :invalid => [ -1, 0, 13, "marc", "sept" ] + :invalid => [ 0, 13, "marc", "sept" ] } } cron = mkcron("valtesting") values.each { |param, hash| - # We have to test the valid ones first, because otherwise the - # state will fail to create at all. - [:valid, :invalid].each { |type| - hash[type].each { |value| + hash.each { |type, values| + values.each { |value| case type when :valid: assert_nothing_raised { diff --git a/test/types/exec.rb b/test/types/exec.rb index 931d649bc..2da818755 100755 --- a/test/types/exec.rb +++ b/test/types/exec.rb @@ -24,11 +24,13 @@ class TestExec < Test::Unit::TestCase assert_nothing_raised { command.evaluate } - assert_events([:executed_command], command) + assert_nothing_raised { + output = command.sync + } + assert_equal([:executed_command],output) end def test_numvsstring -<<<<<<< .working command = nil output = nil assert_nothing_raised { @@ -36,22 +38,7 @@ class TestExec < Test::Unit::TestCase :command => "/bin/echo", :returns => 0 ) -======= - [0, "0"].each { |val| - Puppet.type(:exec).clear - Puppet.type(:component).clear - command = nil - output = nil - assert_nothing_raised { - command = Puppet.type(:exec).create( - :command => "/bin/echo", - :returns => val - ) - } - assert_events([:executed_command], command) ->>>>>>> .merge-right.r784 } -<<<<<<< .working assert_nothing_raised { command.evaluate } @@ -71,8 +58,6 @@ class TestExec < Test::Unit::TestCase assert_nothing_raised { output = command.sync } -======= ->>>>>>> .merge-right.r784 end def test_path_or_qualified @@ -144,7 +129,12 @@ class TestExec < Test::Unit::TestCase :returns => 0 ) } - assert_events([:executed_command], command) + assert_nothing_raised { + command.evaluate + } + assert_nothing_raised { + command.sync + } assert_equal(wd,command.output.chomp) end @@ -157,11 +147,10 @@ class TestExec < Test::Unit::TestCase File.open(tmpfile, File::WRONLY|File::CREAT|File::TRUNC) { |of| of.puts rand(100) } - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => tmpfile, :checksum => "md5" ) - assert_instance_of(Puppet.type(:file), file) assert_nothing_raised { cmd = Puppet::Type::Exec.create( :command => "pwd", @@ -171,9 +160,7 @@ class TestExec < Test::Unit::TestCase ) } - assert_instance_of(Puppet.type(:exec), cmd) - - comp = Puppet.type(:component).create(:name => "RefreshTest") + comp = Puppet::Type::Component.create(:name => "RefreshTest") [file,cmd].each { |obj| comp.push obj } @@ -211,7 +198,6 @@ class TestExec < Test::Unit::TestCase def test_creates file = tempfile() exec = nil - assert(! FileTest.exists?(file), "File already exists") assert_nothing_raised { exec = Puppet::Type::Exec.create( :command => "touch %s" % file, @@ -221,8 +207,8 @@ class TestExec < Test::Unit::TestCase } comp = newcomp("createstest", exec) - assert_events([:executed_command], comp, "creates") - assert_events([], comp, "creates") + assert_events(comp, [:executed_command], "creates") + assert_events(comp, [], "creates") end if Process.uid == 0 @@ -257,7 +243,7 @@ class TestExec < Test::Unit::TestCase } comp = newcomp("usertest", exec) - assert_events([:executed_command], comp, "usertest") + assert_events(comp, [:executed_command], "usertest") assert(FileTest.exists?(file), "File does not exist") if user diff --git a/test/types/file.rb b/test/types/file.rb index 599dc9630..f01440903 100644 --- a/test/types/file.rb +++ b/test/types/file.rb @@ -17,7 +17,7 @@ class TestFile < Test::Unit::TestCase def mkfile(hash) file = nil assert_nothing_raised { - file = Puppet.type(:file).create(hash) + file = Puppet::Type::PFile.create(hash) } return file end @@ -88,14 +88,19 @@ class TestFile < Test::Unit::TestCase us = {} us[uid] = name users.each { |uid, name| - assert_apply(file) + # just make sure we don't try to manage users + assert_nothing_raised() { + file.sync + } assert_nothing_raised() { file[:owner] = name } assert_nothing_raised() { file.retrieve } - assert_apply(file) + assert_nothing_raised() { + file.sync + } } end @@ -120,7 +125,7 @@ class TestFile < Test::Unit::TestCase file = nil assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => path, :owner => user.name, :create => true, @@ -130,7 +135,7 @@ class TestFile < Test::Unit::TestCase comp = newcomp("createusertest", file) - assert_events([:file_created], comp) + assert_events(comp, [:file_created]) end def test_ownerasroot @@ -170,14 +175,19 @@ class TestFile < Test::Unit::TestCase changes << file.evaluate } assert(changes.length > 0) - assert_apply(file) - file.retrieve + assert_nothing_raised() { + file.sync + } + assert_nothing_raised() { + file.evaluate + } assert(file.insync?()) assert_nothing_raised() { file[:owner] = uid } - assert_apply(file) - file.retrieve + assert_nothing_raised() { + file.evaluate + } # make sure changing to number doesn't cause a sync assert(file.insync?()) } @@ -201,8 +211,15 @@ class TestFile < Test::Unit::TestCase } assert(file.state(:group)) assert(file.state(:group).should) - assert_apply(file) - file.retrieve + assert_nothing_raised() { + file.evaluate + } + assert_nothing_raised() { + file.sync + } + assert_nothing_raised() { + file.evaluate + } assert(file.insync?()) assert_nothing_raised() { file.delete(:group) @@ -217,15 +234,22 @@ class TestFile < Test::Unit::TestCase %w{a b c d}.collect { |name| tempfile() + name.to_s }.each { |path| file =nil assert_nothing_raised() { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => path, :create => true ) } - assert_events([:file_created], file) - assert_events([], file) - assert(FileTest.file?(path), "File does not exist") + assert_nothing_raised() { + file.evaluate + } + assert_nothing_raised() { + file.sync + } + assert_nothing_raised() { + file.evaluate + } assert(file.insync?()) + assert(FileTest.file?(path)) @@tmpfiles.push path } end @@ -234,13 +258,20 @@ class TestFile < Test::Unit::TestCase %w{a b c d}.collect { |name| "/tmp/createst%s" % name }.each { |path| file = nil assert_nothing_raised() { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => path, :create => "directory" ) } - assert_events([:directory_created], file) - assert_events([], file) + assert_nothing_raised() { + file.evaluate + } + assert_nothing_raised() { + file.sync + } + assert_nothing_raised() { + file.evaluate + } assert(file.insync?()) assert(FileTest.directory?(path)) @@tmpfiles.push path @@ -249,17 +280,20 @@ class TestFile < Test::Unit::TestCase def test_modes file = mktestfile - # Set it to something else initially - File.chmod(0775, file.name) [0644,0755,0777,0641].each { |mode| assert_nothing_raised() { file[:mode] = mode } - assert_events([:inode_changed], file) - assert_events([], file) - + assert_nothing_raised() { + file.evaluate + } + assert_nothing_raised() { + file.sync + } + assert_nothing_raised() { + file.evaluate + } assert(file.insync?()) - assert_nothing_raised() { file.delete(:mode) } @@ -291,13 +325,13 @@ class TestFile < Test::Unit::TestCase events = nil # okay, we now know that we have a file... assert_nothing_raised() { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => path, :create => true, :checksum => type ) } - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "componentfile" ) comp.push file @@ -325,28 +359,38 @@ class TestFile < Test::Unit::TestCase of.puts rand(100) } } - Puppet.type(:file).clear - Puppet.type(:component).clear + Puppet::Type::PFile.clear + Puppet::Type::Component.clear sleep 1 # now recreate the file assert_nothing_raised() { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => path, :checksum => type ) } - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "componentfile" ) comp.push file trans = nil - assert_events([:file_modified], comp) + assert_nothing_raised() { + trans = comp.evaluate + } + assert_nothing_raised() { + events = trans.evaluate.collect { |e| e.event } + } + + sum = file.state(:checksum) # verify that we're actually getting notified when a file changes + assert( + events.include?(:file_modified) + ) assert_nothing_raised() { - Puppet.type(:file).clear - Puppet.type(:component).clear + Puppet::Type::PFile.clear + Puppet::Type::Component.clear } } } @@ -362,13 +406,13 @@ class TestFile < Test::Unit::TestCase initstorage assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( param => path, :recurse => true, :checksum => "md5" ) } - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push file @@ -378,6 +422,9 @@ class TestFile < Test::Unit::TestCase assert_nothing_raised { trans.evaluate } + #assert_nothing_raised { + # file.sync + #} clearstorage Puppet::Type.allclear } @@ -391,7 +438,7 @@ class TestFile < Test::Unit::TestCase dir = nil assert_nothing_raised { - dir = Puppet.type(:file).create( + dir = Puppet::Type::PFile.create( :path => basedir, :recurse => true, :check => %w{owner mode group} @@ -404,7 +451,7 @@ class TestFile < Test::Unit::TestCase subobj = nil assert_nothing_raised { - subobj = Puppet.type(:file)[subdir] + subobj = Puppet::Type::PFile[subdir] } assert(subobj, "Could not retrieve subdir object") @@ -415,7 +462,7 @@ class TestFile < Test::Unit::TestCase file = nil assert_nothing_raised { - file = Puppet.type(:file)[tmpfile] + file = Puppet::Type::PFile[tmpfile] } assert(file, "Could not retrieve file object") @@ -459,9 +506,8 @@ class TestFile < Test::Unit::TestCase def test_filetype_retrieval file = nil - # Verify it retrieves files of type directory assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => tmpdir(), :check => :type ) @@ -473,27 +519,28 @@ class TestFile < Test::Unit::TestCase assert_equal("directory", file.state(:type).is) - # And then check files assert_nothing_raised { - file = Puppet.type(:file).create( - :name => tempfile(), - :create => true + file = Puppet::Type::PFile.create( + :name => "/etc/passwd", + :check => :type ) } - assert_apply(file) - file[:check] = "type" - assert_apply(file) + assert_nothing_raised { + file.evaluate + } assert_equal("file", file.state(:type).is) - file[:type] = "directory" - - assert_nothing_raised { file.retrieve } + assert_raise(Puppet::Error) { + file[:type] = "directory" + } - # The 'retrieve' method sets @should to @is, so they're never - # out of sync. It's a read-only class. assert(file.insync?) + + assert_raise(Puppet::Error) { + file.sync + } end def test_remove @@ -503,7 +550,7 @@ class TestFile < Test::Unit::TestCase dir = nil assert_nothing_raised { - dir = Puppet.type(:file).create( + dir = Puppet::Type::PFile.create( :path => basedir, :recurse => true, :check => %w{owner mode group} @@ -516,7 +563,7 @@ class TestFile < Test::Unit::TestCase obj = nil assert_nothing_raised { - obj = Puppet.type(:file)[subdir] + obj = Puppet::Type::PFile[subdir] } assert(obj, "Could not retrieve subdir object") @@ -526,7 +573,7 @@ class TestFile < Test::Unit::TestCase } assert_nothing_raised { - obj = Puppet.type(:file)[subdir] + obj = Puppet::Type::PFile[subdir] } assert_nil(obj, "Retrieved removed object") @@ -545,7 +592,7 @@ class TestFile < Test::Unit::TestCase file = nil dirobj = nil assert_nothing_raised("Could not make file object") { - dirobj = Puppet.type(:file).create( + dirobj = Puppet::Type::PFile.create( :path => dir, :recurse => true, :check => %w{mode owner group} diff --git a/test/types/filebucket.rb b/test/types/filebucket.rb index 909170f77..884492c41 100755 --- a/test/types/filebucket.rb +++ b/test/types/filebucket.rb @@ -19,7 +19,7 @@ class TestFileBucket < Test::Unit::TestCase def mkfile(hash) file = nil assert_nothing_raised { - file = Puppet.type(:file).create(hash) + file = Puppet::Type::PFile.create(hash) } return file end @@ -27,7 +27,7 @@ class TestFileBucket < Test::Unit::TestCase def mkbucket(name,path) bucket = nil assert_nothing_raised { - bucket = Puppet.type(:filebucket).create( + bucket = Puppet::Type::PFileBucket.create( :name => name, :path => path ) @@ -77,7 +77,7 @@ class TestFileBucket < Test::Unit::TestCase bucket = nil assert_nothing_raised { - bucket = Puppet.type(:filebucket).bucket(name) + bucket = Puppet::Type::PFileBucket.bucket(name) } assert_instance_of(Puppet::Client::Dipper, bucket) @@ -94,8 +94,6 @@ class TestFileBucket < Test::Unit::TestCase newmd5 = nil - # Just in case the file isn't writable - File.chmod(0644, newpath) File.open(newpath, "w") { |f| f.puts ";lkjasdf;lkjasdflkjwerlkj134lkj" } assert_nothing_raised { @@ -119,7 +117,7 @@ class TestFileBucket < Test::Unit::TestCase bucket = nil assert_nothing_raised { - bucket = Puppet.type(:filebucket).bucket(name) + bucket = Puppet::Type::PFileBucket.bucket(name) } file = mktestfile() @@ -155,7 +153,6 @@ class TestFileBucket < Test::Unit::TestCase File.open(file.name) { |f| newmd5 = Digest::MD5.hexdigest(f.read) } ) - #File.chmod(0644, file.name) assert_nothing_raised { bucket.restore(file.name, origmd5) } diff --git a/test/types/fileignoresource.rb b/test/types/fileignoresource.rb index 688b57845..747fbcfed 100644 --- a/test/types/fileignoresource.rb +++ b/test/types/fileignoresource.rb @@ -76,7 +76,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase #makes Puppet file Object assert_nothing_raised { - tofile = Puppet.type(:file).create( + tofile = Puppet::Type::PFile.create( :name => topath, :source => frompath, :recurse => true, @@ -85,7 +85,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase } #make a component and adds the file - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push tofile @@ -153,7 +153,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase #makes Puppet file Object assert_nothing_raised { - tofile = Puppet.type(:file).create( + tofile = Puppet::Type::PFile.create( :name => topath, :source => frompath, :recurse => true, @@ -162,7 +162,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase } #make a component and adds the file - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push tofile @@ -237,7 +237,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase #makes Puppet file Object assert_nothing_raised { - tofile = Puppet.type(:file).create( + tofile = Puppet::Type::PFile.create( :name => topath, :source => frompath, :recurse => true, @@ -247,7 +247,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase } #make a component and adds the file - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push tofile diff --git a/test/types/filesources.rb b/test/types/filesources.rb index 8dd0ca6b5..b6c8c1b3c 100755 --- a/test/types/filesources.rb +++ b/test/types/filesources.rb @@ -54,7 +54,7 @@ class TestFileSources < Test::Unit::TestCase comp = nil trans = nil assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => path ) } @@ -82,12 +82,12 @@ class TestFileSources < Test::Unit::TestCase of.puts "yayness" } assert_nothing_raised { - tofile = Puppet.type(:file).create( + tofile = Puppet::Type::PFile.create( :name => topath, :source => frompath ) } - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push tofile @@ -97,6 +97,9 @@ class TestFileSources < Test::Unit::TestCase assert_nothing_raised { trans.evaluate } + # assert_nothing_raised { + # comp.sync + # } assert(FileTest.exists?(topath)) from = File.open(frompath) { |o| o.read } @@ -112,14 +115,14 @@ class TestFileSources < Test::Unit::TestCase trans = nil assert_nothing_raised { - tofile = Puppet.type(:file).create( + tofile = Puppet::Type::PFile.create( :name => todir, "recurse" => true, "backup" => false, "source" => fromdir ) } - comp = Puppet.type(:component).create( + comp = Puppet::Type::Component.create( :name => "component" ) comp.push tofile @@ -243,7 +246,7 @@ class TestFileSources < Test::Unit::TestCase File.open(file1, "w") { |f| 3.times { f.print rand(100) } } rootobj = nil assert_nothing_raised { - rootobj = Puppet.type(:file).create( + rootobj = Puppet::Type::PFile.create( :name => basedir, :recurse => true, :check => %w{type owner} @@ -252,7 +255,7 @@ class TestFileSources < Test::Unit::TestCase rootobj.evaluate } - klass = Puppet.type(:file) + klass = Puppet::Type::PFile assert(klass[basedir]) assert(klass[file1]) assert_nil(klass[file2]) @@ -451,7 +454,7 @@ class TestFileSources < Test::Unit::TestCase sleep(1) name = File.join(tmpdir(), "nosourcefile") - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :source => "puppet://localhost/dist/file", :name => name ) @@ -507,7 +510,7 @@ class TestFileSources < Test::Unit::TestCase sleep(1) name = File.join(tmpdir(), "nosourcefile") - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :source => "puppet://localhost/noexist/file", :name => name ) @@ -537,7 +540,7 @@ class TestFileSources < Test::Unit::TestCase # Now the files should be exactly the same, so we should not see attempts # at copying assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => to, :source => from ) @@ -563,14 +566,14 @@ class TestFileSources < Test::Unit::TestCase file = nil assert_nothing_raised { - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :name => to, :source => files ) } comp = newcomp(file) - assert_events([:file_changed], comp) + assert_events(comp, [:file_changed]) assert(File.exists?(to), "File does not exist") diff --git a/test/types/filetype.rb b/test/types/filetype.rb index b3ebf15ff..fe0e4e316 100644 --- a/test/types/filetype.rb +++ b/test/types/filetype.rb @@ -14,10 +14,10 @@ class TestFileType def disabled_setup Puppet[:loglevel] = :debug if __FILE__ == $0 - @passwdtype = Puppet.type(:filetype)["passwd"] + @passwdtype = Puppet::Type::FileType["passwd"] if @passwdtype.nil? assert_nothing_raised() { - @passwdtype = Puppet.type(:filetype).createtype( + @passwdtype = Puppet::Type::FileType.createtype( :name => "passwd" ) @passwdtype.addrecord( @@ -28,10 +28,10 @@ class TestFileType } end - @syslogtype = Puppet.type(:filetype)["syslog"] + @syslogtype = Puppet::Type::FileType["syslog"] if @syslogtype.nil? assert_nothing_raised() { - @syslogtype = Puppet.type(:filetype).createtype( + @syslogtype = Puppet::Type::FileType.createtype( :escapednewlines => true, :name => "syslog" ) @@ -113,7 +113,7 @@ class TestFileType assert(!file.insync?) assert_nothing_raised() { - file.evaluate + file.sync } assert(file.insync?) @@ -125,7 +125,7 @@ class TestFileType assert(!file.insync?) assert_nothing_raised() { - file.evaluate + file.sync } assert(file.insync?) diff --git a/test/types/group.rb b/test/types/group.rb index f28685ef7..215229063 100755 --- a/test/types/group.rb +++ b/test/types/group.rb @@ -19,7 +19,7 @@ class TestGroup < Test::Unit::TestCase end def teardown - Puppet.type(:group).clear + Puppet::Type::Group.clear @@tmpgroups.each { |group| unless missing?(group) remove(group) @@ -99,7 +99,7 @@ class TestGroup < Test::Unit::TestCase group[:gid] = old - trans = assert_events([], comp, "group") + trans = assert_events(comp, [], "group") newgid = old while true @@ -120,7 +120,7 @@ class TestGroup < Test::Unit::TestCase group[:gid] = newgid } - trans = assert_events([:group_modified], comp, "group") + trans = assert_events(comp, [:group_modified], "group") curgid = nil assert_nothing_raised { @@ -144,7 +144,7 @@ class TestGroup < Test::Unit::TestCase assert(obj, "Could not retrieve test group object") - Puppet.type(:group).validstates.each { |name, state| + Puppet::Type::Group.validstates.each { |name, state| assert_nothing_raised { method = state.infomethod assert(method, "State %s has no infomethod" % name) @@ -170,7 +170,7 @@ class TestGroup < Test::Unit::TestCase gobj = nil comp = nil assert_nothing_raised { - gobj = Puppet.type(:group).create( + gobj = Puppet::Type::Group.create( :name => group, :check => [:gid] ) @@ -198,8 +198,8 @@ class TestGroup < Test::Unit::TestCase } user = nil assert_nothing_raised { - checks = Puppet.type(:group).validstates - user = Puppet.type(:group).create( + checks = Puppet::Type::Group.validstates + user = Puppet::Type::Group.create( :name => name, :check => checks ) @@ -234,7 +234,7 @@ class TestGroup < Test::Unit::TestCase assert(missing?(name), "Group %s is still present" % name) assert_nothing_raised { - gobj = Puppet.type(:group).create( + gobj = Puppet::Type::Group.create( :name => name ) @@ -242,7 +242,7 @@ class TestGroup < Test::Unit::TestCase } @@tmpgroups << name - trans = assert_events([:group_created], comp, "group") + trans = assert_events(comp, [:group_created], "group") obj = nil assert_nothing_raised { @@ -250,7 +250,7 @@ class TestGroup < Test::Unit::TestCase } assert(!missing?(name), "Group %s is missing" % name) - tests = Puppet.type(:group).validstates + tests = Puppet::Type::Group.validstates gobj.retrieve tests.each { |test| diff --git a/test/types/package.rb b/test/types/package.rb index 625763d80..c5f781859 100644 --- a/test/types/package.rb +++ b/test/types/package.rb @@ -11,7 +11,7 @@ require 'facter' $platform = Facter["operatingsystem"].value -unless Puppet.type(:package).default +unless Puppet::Type::Package.default puts "No default package type for %s; skipping package tests" % $platform else @@ -31,8 +31,8 @@ class TestPackages < Test::Unit::TestCase include FileTesting def setup super - #@list = Puppet.type(:package).getpkglist - Puppet.type(:package).clear + #@list = Puppet::Type::Package.getpkglist + Puppet::Type::Package.clear end # These are packages that we're sure will be installed @@ -81,7 +81,7 @@ class TestPackages < Test::Unit::TestCase def mkpkgcomp(pkg) assert_nothing_raised { - pkg = Puppet.type(:package).create(:name => pkg, :install => true) + pkg = Puppet::Type::Package.create(:name => pkg, :install => true) } assert_nothing_raised { pkg.retrieve @@ -96,7 +96,7 @@ class TestPackages < Test::Unit::TestCase installedpkgs().each { |pkg| obj = nil assert_nothing_raised { - obj = Puppet.type(:package).create( + obj = Puppet::Type::Package.create( :name => pkg ) } @@ -114,7 +114,7 @@ class TestPackages < Test::Unit::TestCase def test_nosuchpkg obj = nil assert_nothing_raised { - obj = Puppet.type(:package).create( + obj = Puppet::Type::Package.create( :name => "thispackagedoesnotexist" ) } @@ -131,7 +131,7 @@ class TestPackages < Test::Unit::TestCase pkgs = tstpkg || return pkgs.each { |name| - pkg = Puppet.type(:package).create(:name => name) + pkg = Puppet::Type::Package.create(:name => name) assert_nothing_raised { assert(pkg.latest, "Package did not return value for 'latest'") } @@ -147,7 +147,7 @@ class TestPackages < Test::Unit::TestCase # we first set install to 'true', and make sure something gets # installed assert_nothing_raised { - pkg = Puppet.type(:package).create(:name => pkg, :install => true) + pkg = Puppet::Type::Package.create(:name => pkg, :install => true) } assert_nothing_raised { pkg.retrieve @@ -160,7 +160,7 @@ class TestPackages < Test::Unit::TestCase comp = newcomp("package", pkg) - assert_events([:package_installed], comp, "package") + assert_events(comp, [:package_installed], "package") # then uninstall it assert_nothing_raised { @@ -172,7 +172,7 @@ class TestPackages < Test::Unit::TestCase assert(! pkg.insync?, "Package is insync") - assert_events([:package_removed], comp, "package") + assert_events(comp, [:package_removed], "package") # and now set install to 'latest' and verify it installs # FIXME this isn't really a very good test -- we should install @@ -181,7 +181,7 @@ class TestPackages < Test::Unit::TestCase pkg[:install] = "latest" } - assert_events([:package_installed], comp, "package") + assert_events(comp, [:package_installed], "package") pkg.retrieve assert(pkg.insync?, "After install, package is not insync") @@ -195,7 +195,7 @@ class TestPackages < Test::Unit::TestCase assert(! pkg.insync?, "Package is insync") - assert_events([:package_removed], comp, "package") + assert_events(comp, [:package_removed], "package") } end end diff --git a/test/types/query.rb b/test/types/query.rb index f535686cb..86aadf678 100644 --- a/test/types/query.rb +++ b/test/types/query.rb @@ -18,21 +18,21 @@ class TestQuery < Test::Unit::TestCase def file assert_nothing_raised() { cfile = File.join($puppetbase,"examples/root/etc/configfile") - unless Puppet.type(:file).has_key?(cfile) - Puppet.type(:file).create( + unless Puppet::Type::PFile.has_key?(cfile) + Puppet::Type::PFile.create( :path => cfile, :check => [:mode, :owner, :checksum] ) end - @configfile = Puppet.type(:file)[cfile] + @configfile = Puppet::Type::PFile[cfile] } return @configfile end def service assert_nothing_raised() { - unless Puppet.type(:service).has_key?("sleeper") - Puppet.type(:service).create( + unless Puppet::Type::Service.has_key?("sleeper") + Puppet::Type::Service.create( :name => "sleeper", :type => "init", :path => File.join($puppetbase,"examples/root/etc/init.d"), @@ -40,7 +40,7 @@ class TestQuery < Test::Unit::TestCase :check => [:running] ) end - @sleeper = Puppet.type(:service)["sleeper"] + @sleeper = Puppet::Type::Service["sleeper"] } return @sleeper @@ -48,7 +48,7 @@ class TestQuery < Test::Unit::TestCase def component(name,*args) assert_nothing_raised() { - @component = Puppet.type(:component).create(:name => name) + @component = Puppet::Type::Component.create(:name => name) } args.each { |arg| diff --git a/test/types/service.rb b/test/types/service.rb index 30543ea12..99384cf0b 100644 --- a/test/types/service.rb +++ b/test/types/service.rb @@ -17,7 +17,6 @@ class TestService < Test::Unit::TestCase super sleeper = nil script = File.join($puppetbase,"examples/root/etc/init.d/sleeper") - @init = File.join($puppetbase,"examples/root/etc/init.d") @status = script + " status" end @@ -30,10 +29,9 @@ class TestService < Test::Unit::TestCase hash[:name] = "sleeper" hash[:path] = File.join($puppetbase,"examples/root/etc/init.d") hash[:running] = true - hash[:hasstatus] = true - #hash[:type] = "init" + hash[:type] = "init" assert_nothing_raised() { - return Puppet.type(:service).create(hash) + return Puppet::Type::Service.create(hash) } end @@ -42,10 +40,9 @@ class TestService < Test::Unit::TestCase sleeper.retrieve } assert(!sleeper.insync?()) - - comp = newcomp(sleeper) - - assert_events([:service_started], comp) + assert_nothing_raised() { + sleeper.sync + } assert_nothing_raised() { sleeper.retrieve } @@ -66,7 +63,9 @@ class TestService < Test::Unit::TestCase sleeper.retrieve } assert(!sleeper.insync?()) - assert_events([:service_stopped], comp) + assert_nothing_raised() { + sleeper.sync + } assert_nothing_raised() { sleeper.retrieve } @@ -84,26 +83,18 @@ class TestService < Test::Unit::TestCase cyclesleeper(sleeper) end - def test_invalidpathsremoved - sleeper = mksleeper() - fakedir = [@init, "/thisdirnoexist"] - sleeper[:path] = fakedir - - assert(! sleeper[:path].include?(fakedir)) + unless Process.uid == 0 + puts "run as root to test service enable/disable" + else + case Puppet::Type::Service.defaulttype + when Puppet::ServiceTypes::InitSvc + when Puppet::ServiceTypes::SMFSvc + # yay + else + Puppet.notice "Not testing service type %s" % + Puppet::Type::Service.defaulttype + end end - - #unless Process.uid == 0 - # puts "run as root to test service enable/disable" - #else - # case Puppet.type(:service).defaulttype - # when Puppet::ServiceTypes::InitSvc - # when Puppet::ServiceTypes::SMFSvc - # # yay - # else - # Puppet.notice "Not testing service type %s" % - # Puppet.type(:service).defaulttype - # end - #end end # $Id$ diff --git a/test/types/symlink.rb b/test/types/symlink.rb index ecaf8d3ae..3d288bc0a 100755 --- a/test/types/symlink.rb +++ b/test/types/symlink.rb @@ -41,7 +41,7 @@ class TestSymlink < Test::Unit::TestCase unless hash.include?(:target) hash[:target] = mktmpfile() end - link = Puppet.type(:symlink).create(hash) + link = Puppet::Type::Symlink.create(hash) return link end @@ -56,7 +56,9 @@ class TestSymlink < Test::Unit::TestCase } # we might already be in sync assert(!link.insync?()) - assert_apply(link) + assert_nothing_raised() { + link.sync + } assert_nothing_raised() { link.retrieve } diff --git a/test/types/tidy.rb b/test/types/tidy.rb index b61c68b14..02068b6ff 100755 --- a/test/types/tidy.rb +++ b/test/types/tidy.rb @@ -37,7 +37,7 @@ class TestTidy < Test::Unit::TestCase f.puts rand(100) } - tidy = Puppet.type(:tidy).create( + tidy = Puppet::Type::Tidy.create( :name => dir, :size => "1b", :recurse => true @@ -67,7 +67,7 @@ class TestTidy < Test::Unit::TestCase f.puts rand(100) } - tidy = Puppet.type(:tidy).create( + tidy = Puppet::Type::Tidy.create( :name => dir, :size => "1b", :age => "1s", diff --git a/test/types/type.rb b/test/types/type.rb index ecb623123..87ca8077a 100644 --- a/test/types/type.rb +++ b/test/types/type.rb @@ -52,7 +52,7 @@ class TestType < Test::Unit::TestCase path = tempfile() assert_nothing_raised() { system("rm -f %s" % path) - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( :path => path, :create => true, :recurse => true, @@ -63,12 +63,12 @@ class TestType < Test::Unit::TestCase file.retrieve } assert_nothing_raised() { - file.evaluate + file.sync } - Puppet.type(:file).clear + Puppet::Type::PFile.clear assert_nothing_raised() { system("rm -f %s" % path) - file = Puppet.type(:file).create( + file = Puppet::Type::PFile.create( "path" => path, "create" => true, "recurse" => true, @@ -91,7 +91,7 @@ class TestType < Test::Unit::TestCase file["recurse"] } assert_nothing_raised() { - file.evaluate + file.sync } end @@ -102,7 +102,7 @@ class TestType < Test::Unit::TestCase # currently groups are the only objects with the namevar as a state group = nil assert_nothing_raised { - group = Puppet.type(:group).create( + group = Puppet::Type::Group.create( :name => "testing" ) } @@ -116,7 +116,7 @@ class TestType < Test::Unit::TestCase # Create the first version assert_nothing_raised { - Puppet.type(:file).create( + Puppet::Type::PFile.create( :path => file, :owner => ["root", "bin"] ) @@ -124,7 +124,7 @@ class TestType < Test::Unit::TestCase # Make sure no other statements are allowed assert_raise(Puppet::Error) { - Puppet.type(:file).create( + Puppet::Type::PFile.create( :path => file, :group => "root" ) diff --git a/test/types/user.rb b/test/types/user.rb index db2acf52a..4408cfa4b 100755 --- a/test/types/user.rb +++ b/test/types/user.rb @@ -42,7 +42,7 @@ class TestUser < Test::Unit::TestCase end def current?(param, name) - state = Puppet.type(:user).states.find { |st| + state = Puppet::Type::User.states.find { |st| st.name == param } @@ -80,7 +80,7 @@ class TestUser < Test::Unit::TestCase end def current?(param, name) - state = Puppet.type(:user).states.find { |st| + state = Puppet::Type::User.states.find { |st| st.name == param } @@ -112,7 +112,7 @@ class TestUser < Test::Unit::TestCase def mkuser(name) user = nil assert_nothing_raised { - user = Puppet.type(:user).create( + user = Puppet::Type::User.create( :name => name, :comment => "Puppet Testing User", :gid => Process.gid, @@ -130,7 +130,7 @@ class TestUser < Test::Unit::TestCase comp = newcomp("commenttest", user) - trans = assert_events([:user_modified], comp, "user") + trans = assert_events(comp, [:user_modified], "user") assert_equal("A different comment", current?(:comment, user[:name]), "Comment was not changed") @@ -148,11 +148,11 @@ class TestUser < Test::Unit::TestCase old = current?(:home, user[:name]) user[:home] = old - trans = assert_events([], comp, "user") + trans = assert_events(comp, [], "user") user[:home] = "/tmp" - trans = assert_events([:user_modified], comp, "user") + trans = assert_events(comp, [:user_modified], "user") assert_equal("/tmp", current?(:home, user[:name]), "Home was not changed") @@ -167,7 +167,7 @@ class TestUser < Test::Unit::TestCase user[:shell] = old - trans = assert_events([], comp, "user") + trans = assert_events(comp, [], "user") newshell = findshell(old) @@ -178,7 +178,7 @@ class TestUser < Test::Unit::TestCase user[:shell] = newshell - trans = assert_events([:user_modified], comp, "user") + trans = assert_events(comp, [:user_modified], "user") assert_equal(newshell, current?(:shell, user[:name]), "Shell was not changed") @@ -197,7 +197,7 @@ class TestUser < Test::Unit::TestCase user[:gid] = old - trans = assert_events([], comp, "user") + trans = assert_events(comp, [], "user") newgid = %w{nogroup nobody staff users daemon}.find { |gid| begin @@ -218,7 +218,7 @@ class TestUser < Test::Unit::TestCase user[:gid] = newgid } - trans = assert_events([:user_modified], comp, "user") + trans = assert_events(comp, [:user_modified], "user") # then by id newgid = Etc.getgrnam(newgid).gid @@ -229,7 +229,7 @@ class TestUser < Test::Unit::TestCase user.retrieve - assert_events([], comp, "user") + assert_events(comp, [], "user") assert_equal(newgid, current?(:gid,user[:name]), "GID was not changed") @@ -245,7 +245,7 @@ class TestUser < Test::Unit::TestCase old = current?(:uid, user[:name]) user[:uid] = old - trans = assert_events([], comp, "user") + trans = assert_events(comp, [], "user") newuid = old while true @@ -266,7 +266,7 @@ class TestUser < Test::Unit::TestCase user[:uid] = newuid } - trans = assert_events([:user_modified], comp, "user") + trans = assert_events(comp, [:user_modified], "user") assert_equal(newuid, current?(:uid, user[:name]), "UID was not changed") @@ -281,7 +281,7 @@ class TestUser < Test::Unit::TestCase assert(obj, "Could not retrieve test group object") - Puppet.type(:user).validstates.each { |name| + Puppet::Type::User.validstates.each { |name| assert_nothing_raised { method = state.posixmethod assert(method, "State %s has no infomethod" % name) @@ -301,8 +301,8 @@ class TestUser < Test::Unit::TestCase } user = nil assert_nothing_raised { - checks = Puppet.type(:user).validstates - user = Puppet.type(:user).create( + checks = Puppet::Type::User.validstates + user = Puppet::Type::User.create( :name => name, :check => checks ) @@ -327,7 +327,7 @@ class TestUser < Test::Unit::TestCase comp = newcomp("usercomp", user) - trans = assert_events([:user_created], comp, "user") + trans = assert_events(comp, [:user_created], "user") assert_equal("Puppet Testing User", current?(:comment, user[:name]), "Comment was not set") @@ -349,12 +349,12 @@ class TestUser < Test::Unit::TestCase comp = newcomp("usercomp", user) - trans = assert_events([:user_created], comp, "user") + trans = assert_events(comp, [:user_created], "user") assert_equal("Puppet Testing User", current?(:comment, user[:name]), "Comment was not set") - tests = Puppet.type(:user).validstates + tests = Puppet::Type::User.validstates user.retrieve tests.each { |test| |