diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-01-13 17:07:15 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-01-13 17:07:15 +0000 |
| commit | 0c1714945692330ca76a6c254303ff4fcd466efb (patch) | |
| tree | a0ec98b6fe19c10fe7572a1bf1cfa6ab65e30f27 /lib | |
| parent | df6ff9eea936c030218853c1ad8ac1b7d2666eaf (diff) | |
| download | puppet-0c1714945692330ca76a6c254303ff4fcd466efb.tar.gz puppet-0c1714945692330ca76a6c254303ff4fcd466efb.tar.xz puppet-0c1714945692330ca76a6c254303ff4fcd466efb.zip | |
finalizing cron and host management, hopefully
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@820 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/puppet/type.rb | 5 | ||||
| -rwxr-xr-x | lib/puppet/type/cron.rb | 84 | ||||
| -rwxr-xr-x | lib/puppet/type/parsedtype.rb | 31 | ||||
| -rwxr-xr-x | lib/puppet/type/parsedtype/host.rb (renamed from lib/puppet/type/host.rb) | 0 | ||||
| -rw-r--r-- | lib/puppet/type/typegen.rb | 117 | ||||
| -rw-r--r-- | lib/puppet/type/typegen/filerecord.rb | 186 | ||||
| -rw-r--r-- | lib/puppet/type/typegen/filetype.rb | 286 |
7 files changed, 36 insertions, 673 deletions
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 019ce190b..eb0cc8282 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -1748,7 +1748,6 @@ require 'puppet/type/component' require 'puppet/type/cron' require 'puppet/type/exec' require 'puppet/type/group' -require 'puppet/type/host' require 'puppet/type/package' require 'puppet/type/pfile' require 'puppet/type/pfilebucket' @@ -1756,8 +1755,6 @@ require 'puppet/type/service' require 'puppet/type/symlink' require 'puppet/type/user' require 'puppet/type/tidy' -#require 'puppet/type/typegen' -#require 'puppet/type/typegen/filetype' -#require 'puppet/type/typegen/filerecord' +require 'puppet/type/parsedtype' # $Id$ diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 61f262015..eca07c10e 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -2,6 +2,7 @@ require 'etc' require 'facter' require 'puppet/type/state' require 'puppet/filetype' +require 'puppet/type/parsedtype' module Puppet # Model the actual cron jobs. Supports all of the normal cron job fields @@ -10,46 +11,14 @@ module Puppet # and is used to manage the job. newtype(:cron) do # A base class for all of the Cron parameters, since they all have - # similar argument checking going on. - class CronParam < Puppet::State + # similar argument checking going on. We're stealing the base class + # from parsedtype, and we should probably subclass Cron from there, + # but it was just too annoying to do. + class CronParam < Puppet::State::ParsedParam class << self attr_accessor :boundaries end - # 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(nostore = false) - event = nil - if @is == :notfound - @is = self.should - event = :cron_created - elsif self.should == :notfound - @parent.remove(true) - event = :cron_deleted - elsif self.insync? - return nil - else - @is = self.should - event = :cron_changed - end - - unless nostore - @parent.store - end - - return event - end - # A method used to do parameter input handling. Converts integers # in string form to actual integers, and returns the value if it's # an integer or false if it's just a normal string. @@ -110,6 +79,7 @@ module Puppet # a boolean of whether to do alpha checking, and if so requires # the ary against which to do the checking. munge do |value| + return value unless self.class.boundaries lower, upper = self.class.boundaries retval = nil if num = numfix(value) @@ -136,52 +106,12 @@ module Puppet # # 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 + newstate(:command, CronParam) 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 - end end newstate(:minute, CronParam) do diff --git a/lib/puppet/type/parsedtype.rb b/lib/puppet/type/parsedtype.rb index 0add210d1..c942c1217 100755 --- a/lib/puppet/type/parsedtype.rb +++ b/lib/puppet/type/parsedtype.rb @@ -1,14 +1,26 @@ require 'etc' require 'facter' +require 'puppet/filetype' require 'puppet/type/state' module Puppet class State + # The base parameter for all of these types. Its only job is to copy + # the 'should' value to the 'is' value and to do support the right logging + # and such. class ParsedParam < Puppet::State @name = :parsedparam # Normally this would retrieve the current value, but our state is not # actually capable of doing so. def retrieve + # If we've synced, then just copy the values over and return. + # This allows this state to behave like any other state. + if defined? @synced and @synced + @is = self.should + @synced = false + return + end + unless defined? @is and ! @is.nil? @is = :notfound end @@ -18,17 +30,28 @@ module Puppet # out which event to return. Finally, call @parent.sync to write the # host tab. def sync(nostore = false) - ebase = @parent.class + ebase = @parent.class.name.to_s if @is == :notfound @is = self.should tail = "created" + + # If we're creating it, then sync all of the other states + # but tell them not to store (we'll store just once, + # at the end). + @parent.eachstate { |state| + next if state == self + state.sync(true) + } elsif self.should == :notfound @parent.remove(true) tail = "deleted" elsif self.insync? return nil else - @is = self.should + #@is = self.should + # Mark that we've synced it, but don't copy the value, because + # that will make the 'change' log inscrutable. + @synced = true tail = "changed" end @@ -41,7 +64,7 @@ module Puppet end end - class Type + class Type # :nodoc: # The collection of classes that are just simple records aggregated # into a file. See 'host.rb' for an example. class ParsedType < Puppet::Type @@ -195,4 +218,6 @@ module Puppet end end +require 'puppet/type/parsedtype/host' + # $Id$ diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/parsedtype/host.rb index 4b60e7142..4b60e7142 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/parsedtype/host.rb diff --git a/lib/puppet/type/typegen.rb b/lib/puppet/type/typegen.rb deleted file mode 100644 index d0a55e081..000000000 --- a/lib/puppet/type/typegen.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'etc' -require 'puppet/type' - -module Puppet -class Type -class TypeGenerator < Puppet::Type - include Enumerable - - @doc = "..." - @namevar = :name - @name = :typegen - @abstract = true - - @parameters = [:name] - @states = [] - - @paramdoc[:name] = "..." - - class << self - attr_accessor :name - end - - def TypeGenerator.[](name) - return @subclasses[name] - end - - def TypeGenerator.initvars - @subclasses = Hash.new(nil) - super - end - - def TypeGenerator.namevar - return @namevar || :name - end - - def TypeGenerator.namevar=(namevar) - Puppet.debug "Setting namevar for %s to %s" % [self,namevar] - unless namevar.is_a? Symbol - namevar = namevar.intern - end - @namevar = namevar - end - - def TypeGenerator.newtype(arghash) - unless defined? @parameters - raise "Type %s is set up incorrectly" % self - end - - arghash.each { |key,value| - if key.class != Symbol - # convert to a symbol - arghash[key.intern] = value - arghash.delete key - key = key.intern - end - unless @parameters.include?(key) - raise "Invalid argument %s on class %s" % - [key,self] - end - - } - - # turn off automatically checking all arguments - #@parameters.each { |option| - # unless arghash.include?(option) - # p arghash - # raise "Must pass %s to class %s" % - # [option,self] - # end - #} - - if @subclasses.include?(arghash[:name]) - raise "File type %s already exists" % arghash[:name] - end - - klassname = arghash[:name].capitalize - - # create the file type - Puppet::Type.module_eval " - class %s < %s - end" % [klassname,self] - klass = eval(klassname) - klass.name = arghash[:name] - - @subclasses[arghash[:name]] = klass - - arghash.each { |option,value| - method = option.id2name + "=" - if klass.respond_to?(method) - #debug "Setting %s on %s to '%s'" % [option,klass,arghash[option]] - klass.send(method,arghash[option]) - else - debug "%s does not respond to %s" % [klass,method] - end - } - - # i couldn't get the method definition stuff to work - # oh well - # probably wouldn't want it in the end anyway - #@parameters.each { |option| - # writer = option.id2name + "=" - # readproc = proc { eval("@" + option.id2name) } - # klass.send(:define_method,option,readproc) - # writeproc = proc { |value| module_eval("@" + option.id2name) = value } - # klass.send(:define_method,writer,writeproc) - # klass.send(writer,hash[option]) - #} - - #Puppet::Type.inherited(klass) - Puppet::Type.buildtypehash - return klass - end -end -end -end - -# $Id$ diff --git a/lib/puppet/type/typegen/filerecord.rb b/lib/puppet/type/typegen/filerecord.rb deleted file mode 100644 index 537523463..000000000 --- a/lib/puppet/type/typegen/filerecord.rb +++ /dev/null @@ -1,186 +0,0 @@ - -# parse and write configuration files using objects with minimal parsing abilities - -require 'etc' -require 'puppet/type' -require 'puppet/type/typegen' - -class Puppet.type(:filerecord) < Puppet::Type::TypeGenerator - class << self - # The name of the record type. Probably superfluous. - attr_accessor :name - - # What character we split on to convert from a line into a set of fields. - # This can be either a string or a regex and defaults to /\s+/ - attr_accessor :fieldsep - - # The fields in this record type. - attr_accessor :fields - - # Which of the fields counts as the name of the record. Defaults to the - # first field. - attr_accessor :namevar - - # Which filetype this record type is associated with. Essentially useless. - attr_accessor :filetype - - # An optional regex to use to match fields. This can be used instead - # of splitting based on a character and must use match sets to return - # the fields. If this is not set, then a regex is created from the - # fieldsep. If your regex is complicated enough that you have nested - # parentheses, then just set your fields up so that the non-field matches - # are nil. - attr_writer :regex - - # The character(s) to use to join the records back together. If this is - # not set, then 'fieldsep' will be used instead, which means that this - # *must* be set if 'fieldsep' is a regex or if the record regex is set. - attr_accessor :fieldjoin - - # Some records (like cron jobs) don't have a name field, so we have to - # store the name in the previous comment. Dern. If we are doing this, - # it is assumed that some objects won't yet have names, so we'll generate - # names for those cases. - attr_accessor :extname - end - - def FileRecord.newtype(hash) - # Provide some defaults. - newklass = Class.new(self) - - # If they've passed in values, then set them appropriately. - unless hash.empty? - hash.each { |param, val| - meth = param.to_s + "=" - if self.respond_to? meth - self.send(meth, val) - end - } - end - - # If they've provided a block, then yield to it - if block_given? - yield newklass - end - - return newklass - end - - def FileRecord.match(object,line) - matchobj = nil - begin - matchobj = self.regex.match(line) - rescue RegexpError => detail - raise - end - - if matchobj.nil? - return nil - else - child = self.new(object) - child.match = matchobj - return child - end - end - - def FileRecord.regex - # the only time @regex is allowed to be nil is if @fieldsep is defined - if @regex.nil? - if @fieldsep.nil? - raise Puppet::DevError, - "%s defined incorrectly -- fieldsep or regex must be specified" % - self - else - ary = [] - text = @fields.collect { |field| - "([^%s]*)" % @fieldsep - }.join(@fieldsep) - begin - @regex = Regexp.new(text) - rescue RegexpError => detail - raise Puppet::DevError, - "Could not create splitregex from %s" % @fieldsep - end - debug("Created regexp %s" % @regex) - end - elsif @regex.is_a?(String) - begin - @regex = Regexp.new(@regex) - rescue RegexpError => detail - raise Puppet::DevError, "Could not create splitregex from %s" % @regex - end - end - return @regex - end - - def ==(other) - unless self.class == other.class - return false - end - - unless self.name == other.name - return false - end - @parameters.keys { |field| - unless self[field] == other[field] - debug("%s -> %s has changed" % [self.name, field]) - return false - end - } - return true - end - - def initialize(hash) - if self.class == Puppet.type(:filerecord) - self.class.newtype(hash) - return - end - @parameters = {} - #if block_given? - # yield self - #end - super(hash) - end - - def match=(matchobj) - @match = matchobj - #puts "captures are [%s]" % [matchobj.captures] - self.class.fields.zip(matchobj.captures) { |field,value| - @parameters[field] = value - #puts "%s => %s" % [field,@parameters[field]] - } - end - - def record=(record) - begin - ary = record.split(self.class.regex) - rescue RegexpError => detail - raise RegexpError.new(detail) - end - self.class.fields.each { |field| - @parameters[field] = ary.shift - #puts "%s => %s" % [field,@parameters[field]] - } - end - - def name - if @parameters.include?(self.class.namevar) - return @parameters[self.class.namevar] - else - raise "No namevar '%s' for objects of type %s" % - [self.class.namevar,self.class.to_s] - end - end - - def to_s - ary = self.class.fields.collect { |field| - if ! @parameters.include?(field) - raise "Object %s is missing field %s" % [self.name,field] - else - @parameters[field] - end - }.join(self.class.fieldjoin || self.class.fieldsep) - end -end - -# $Id$ diff --git a/lib/puppet/type/typegen/filetype.rb b/lib/puppet/type/typegen/filetype.rb deleted file mode 100644 index 9fc6b41f0..000000000 --- a/lib/puppet/type/typegen/filetype.rb +++ /dev/null @@ -1,286 +0,0 @@ -# parse and write configuration files using objects with minimal parsing abilities - -require 'puppet/type' -require 'puppet/type/typegen' - -class Puppet.type(:filetype) < Puppet::Type::TypeGenerator - @parameters = [:name, :recordsep, :escapednewlines] - - @namevar = :name - @name = :filetype - - @modsystem = true - - class << self - # Which field in the record functions as the name of the record. - attr_accessor :namevar - - # Does this filetype support escaped newlines? Defaults to false. - attr_accessor :escapednewlines - - # What do comments in this filetype look like? Defaults to /^#|^\s/ - attr_accessor :comment - - # What is the record separator? Defaults to "\n". - attr_accessor :recordsep - - # How do we separate records? Normally we just turn the recordsep - # into a regex, but you can override that, or just not use the recordsep. - attr_writer :regex - end - - # 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) - raise Puppet::DevError, "Cannot add records to the FileType base class" - end - - newrecord = Puppet.type(:filerecord).newtype(hash) - newrecord.filetype = self - - if block_given? - yield newrecord - end - - unless defined? @records - @records = [] - end - - @records << newrecord - end - - # Remove all defined filetypes. Mostly used for testing. - def self.clear - if defined? @subclasses - @subclasses.each { |sub| - sub.clear - } - @subclasses.clear - end - - if defined? @records - @records.clear - end - end - - # Yield each record in turn, so we can iterate over each of them. - def self.eachrecord - @records.each { |record| - yield record - } - end - - # Create a new file type. You would generally provide an initialization block - # for this method: - # - # FileType.newtype do |type| - # @name = "cron" - # type.addrecord do |record| - # @name = "cronjob" - # @splitchar = "\t" - # @fields = [:minute, :hour, :monthday, :month, :weekday, :command] - # end - # end - # - # You don't actually have to provide anything at initialization time, but your - # filetype won't be much use if you don't at least provide it with some record - # types. You will generally only have one record type, since comments are - # handled transparently, although you might have to define what looks like a - # comment (the default is anything starting with a '#' or any whitespace). - def FileType.newtype(hash = {}) - unless defined? @subclasses - @subclasses = Hash.new - end - - # Provide some defaults. - newklass = Class.new(self) do - @escapednewlines = true - @namevar = :name - @comment = /^#|^\s/ - @recordsep = "\n" - end - - # If they've passed in values, then set them appropriately. - unless hash.empty? - hash.each { |param, val| - meth = param.to_s + "=" - if self.respond_to? meth - self.send(meth, val) - end - } - end - - # If they've provided a block, then yield to it - if block_given? - yield newklass - end - - @subclasses << newklass - return newklass - end - - # Return the defined regex or the recordsep converted to one. - def FileType.regex - unless defined? @regex - @regex = %r{#{recordsep}} - end - return @regex - end - - # we don't really have a 'less-than/greater-than' sense here - # so i'm sticking with 'equals' until those make sense - def ==(other) - unless self.children.length == other.children.length - Puppet.debug("file has %s records instead of %s" % - [self.children.length, other.children.length]) - return self.children.length == other.children.length - end - equal = true - self.zip(other.children) { |schild,ochild| - unless schild == ochild - Puppet.debug("%s has changed in %s" % - [schild.name,self.name]) - equal = false - break - end - } - - return equal - end - - # create a new record with a block - def add(type,&block) - obj = self.class.records[type].new(self,&block) - debug("adding %s" % obj.name) - @childary.push(obj) - @childhash[obj.name] = obj - - return obj - end - - def children - return @childary - end - - # remove a record - def delete(name) - if @childhash.has_key?(name) - child = @childhash[name] - - @childhash.delete(child) - @childary.delete(child) - else - raise "No such entry %s" % name - end - end - - def each - @childary.each { |child| - yield child - } - end - - # create a new file - def initialize(hash) - # 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) - self.class.newtype(hash) - return - end - debug "Creating new '%s' file with path '%s' and name '%s'" % - [self.class.name,hash["path"],hash[:name]] - debug hash.inspect - @file = hash["path"] - - @childary = [] - @childhash = {} - super - end - - # this is where we're pretty different from other objects - # we can choose to either reparse the existing file and compare - # the objects, or we can write our file out and do an - # text comparison - def insync? - tmp = self.class.new(@file) - tmp.retrieve - - return self == tmp - end - - #def name - # return @file - #end - - # read the whole file in and turn it into each of the appropriate - # objects - def retrieve - str = "" - ::File.open(@file) { |fname| - fname.each { |line| - str += line - } - } - - if self.class.escapednewlines - endreg = %r{\\\n\s*} - str.gsub!(endreg,'') - end - @childary = str.split(self.class.regex).collect { |line| - childobj = nil - self.class.records.each { |name,recordtype| - if childobj = recordtype.match(self,line) - break - end - } - if childobj.nil? - warning("%s: could not match %s" % [self.name,line]) - #warning("could not match %s" % line) - next - end - - begin - debug("got child: %s(%s)" % [childobj.class,childobj.to_s]) - rescue NoMethodError - warning "Failed: %s" % childobj - end - childobj - }.reject { |child| - child.nil? - } - - @childary.each { |child| - begin - @childhash[child.name] = child - rescue NoMethodError => detail - p child - p child.class - puts detail - exit - end - } - end - - def sync - #unless self.insync? - self.write - #end - end - - def to_s - return @childary.collect { |child| - child.to_s - }.join(self.class.recordsep) + self.class.recordsep - end - - def write - ::File.open(@file, "w") { |file| - file.write(self.to_s) - } - end -end - -# $Id$ |
