summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-01-13 17:07:15 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-01-13 17:07:15 +0000
commit0c1714945692330ca76a6c254303ff4fcd466efb (patch)
treea0ec98b6fe19c10fe7572a1bf1cfa6ab65e30f27 /lib
parentdf6ff9eea936c030218853c1ad8ac1b7d2666eaf (diff)
downloadpuppet-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.rb5
-rwxr-xr-xlib/puppet/type/cron.rb84
-rwxr-xr-xlib/puppet/type/parsedtype.rb31
-rwxr-xr-xlib/puppet/type/parsedtype/host.rb (renamed from lib/puppet/type/host.rb)0
-rw-r--r--lib/puppet/type/typegen.rb117
-rw-r--r--lib/puppet/type/typegen/filerecord.rb186
-rw-r--r--lib/puppet/type/typegen/filetype.rb286
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$