diff options
Diffstat (limited to 'lib/puppet')
-rwxr-xr-x | lib/puppet/filetype.rb | 6 | ||||
-rw-r--r-- | lib/puppet/parameter.rb | 12 | ||||
-rw-r--r-- | lib/puppet/type.rb | 27 | ||||
-rwxr-xr-x | lib/puppet/type/cron.rb | 33 | ||||
-rwxr-xr-x | lib/puppet/type/parsedtype.rb | 143 | ||||
-rwxr-xr-x | lib/puppet/type/parsedtype/host.rb | 15 | ||||
-rwxr-xr-x | lib/puppet/type/parsedtype/port.rb | 80 | ||||
-rwxr-xr-x | lib/puppet/type/parsedtype/sshkey.rb | 10 | ||||
-rw-r--r-- | lib/puppet/type/state.rb | 97 |
9 files changed, 218 insertions, 205 deletions
diff --git a/lib/puppet/filetype.rb b/lib/puppet/filetype.rb index f67382b56..6525204ab 100755 --- a/lib/puppet/filetype.rb +++ b/lib/puppet/filetype.rb @@ -40,7 +40,11 @@ module Puppet begin val = real_read() @loaded = Time.now - return val.gsub(/# HEADER.*\n/,'') + if val + return val.gsub(/# HEADER.*\n/,'') + else + return "" + end rescue Puppet::Error => detail raise rescue => detail diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb index 82fa1bb0f..a3a935b00 100644 --- a/lib/puppet/parameter.rb +++ b/lib/puppet/parameter.rb @@ -290,7 +290,17 @@ module Puppet # it possible to call for states, too. def value if self.is_a?(Puppet::State) - return self.should + # We should return the 'is' value if there's not 'should' value. + # This might be bad, though, because the 'should' method + # knows whether to return an array or not and that info is + # not exposed, and the 'is' value could be a symbol. I can't + # seem to create a test in which this is a problem, but that doesn't + # mean it's not one. + if self.should + return self.should + else + return self.is + end else if defined? @value return @value diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index cb05cb847..0c0fc2d98 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -1658,23 +1658,9 @@ class Type < Puppet::Element @evalcount = 0 end @@retrieved[self] += 1 - # if we're a metaclass and we've already evaluated once... - #if self.metaclass and @evalcount > 0 - # return - #end @evalcount += 1 - #changes = @children.collect { |child| - # child.evaluate - #} - changes = [] - # collect all of the changes from children and states - #if self.class.depthfirst? - # changes << self.collect { |child| - # child.evaluate - # } - #end # this only operates on states, not states + children # it's important that we call retrieve() on the type instance, @@ -1698,16 +1684,6 @@ class Type < Puppet::Element child.cache(:checked, now) ch } - #unless self.class.depthfirst? - # changes << self.collect { |child| - # child.evaluate - # } - #end - # collect changes and return them - # these changes could be from child objects or from contained states - #self.collect { |child| - # child.evaluate - #} if self.class.depthfirst? changes += statechanges() @@ -1720,9 +1696,6 @@ class Type < Puppet::Element if changes.length > 0 self.info "%s change(s)" % [changes.length] - #changes.each { |change| - # self.debug "change: %s" % change.state.name - #} end self.cache(:checked, now) return changes.flatten diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 7e44125a2..978901a98 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -103,6 +103,11 @@ 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| + # Support 'absent' as a value, so that they can remove + # a value + if value == "absent" or value == :absent + return :absent + end return value unless self.class.boundaries lower, upper = self.class.boundaries retval = nil @@ -135,7 +140,10 @@ module Puppet 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." + user's environment is desired it should be sourced manually. + + All cron parameters support ``absent`` as a value; this will + remove any existing values for that field." end newstate(:minute, CronParam) do @@ -178,12 +186,13 @@ module Puppet newparam(:name) do desc "The symbolic name of the cron job. This name - is used for human reference only and is generated - automatically for cron jobs found on the system. This generally - won't matter, as Puppet will do its best to match existing - cron jobs against specified jobs (and Puppet adds a tag to - cron jobs it adds), but it is at least possible that converting - from unmanaged jobs to managed jobs might require manual intervention." + is used for human reference only and is generated automatically + for cron jobs found on the system. This generally won't + matter, as Puppet will do its best to match existing cron jobs + against specified jobs (and Puppet adds a tag to cron jobs it + adds), but it is at least possible that converting from + unmanaged jobs to managed jobs might require manual + intervention." isnamevar end @@ -487,7 +496,9 @@ module Puppet def exists? val = false - if @states.include?(:command) and @states[:command].is != :absent + if @states.include?(:command) and + @states[:command].is != :absent and + ! @states[:command].is.nil? val = true end return val @@ -523,7 +534,11 @@ module Puppet return "# Puppet Name: %s\n" % self.name + self.class.fields.collect { |f| - hash[f] || "*" + if hash[f] and hash[f] != :absent + hash[f] + else + "*" + end }.join(" ") end end diff --git a/lib/puppet/type/parsedtype.rb b/lib/puppet/type/parsedtype.rb index 2048ba934..0429bcdd1 100755 --- a/lib/puppet/type/parsedtype.rb +++ b/lib/puppet/type/parsedtype.rb @@ -9,6 +9,31 @@ module Puppet # the 'should' value to the 'is' value and to do support the right logging # and such. class ParsedParam < Puppet::State + def self.isoptional + @isoptional = true + end + + def self.isoptional? + if defined? @isoptional + return @isoptional + else + return false + end + end + + # By default, support ':absent' as a value for optional + # parameters. Any parameters that define their own validation + # need to do this manuallly. + validate do |value| + if self.class.isoptional? and ( + value == "absent" or value == :absent + ) + return :absent + else + return value + end + end + # Fix things so that the fields have to match exactly, instead # of only kinda def insync? @@ -32,40 +57,39 @@ module Puppet end end - # Determine whether the host entry should be destroyed, and figure - # out which event to return. Finally, call @parent.sync to write the - # host tab. + # If the ensure state is out of sync, it will always be called + # first, so I don't need to worry about that. def sync(nostore = false) ebase = @parent.class.name.to_s - if @is == :absent - #@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). - unless nostore - @parent.eachstate { |state| - next if state == self or state.name == :ensure - state.sync(true) - } + + tail = nil + if self.class.name == :ensure + # We're either creating or destroying the object + if @is == :absent + #@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). + unless nostore + @parent.eachstate { |state| + next if state == self or state.name == :ensure + state.sync(true) + } + end + elsif self.should == :absent + @parent.remove(true) + tail = "deleted" end - elsif self.should == :absent - @parent.remove(true) - tail = "deleted" - #elsif @is == @should - elsif self.insync? - self.info "Already in sync: %s vs %s" % - [@is.inspect, @should.inspect] - return nil else - #@is = self.should - # Mark that we've synced it, but don't copy the value, because - # that will make the 'change' log inscrutable. + # We don't do the work here, it gets done in 'store' tail = "changed" end @synced = self.should + # This should really only be done once per run, rather than + # every time. I guess we need some kind of 'flush' mechanism. if nostore self.retrieve else @@ -106,7 +130,7 @@ module Puppet super end - # In addition to removing the instances in @objects, Cron has to remove + # In addition to removing the instances in @objects, we have to remove # per-user host tab information. def self.clear @instances = [] @@ -126,8 +150,9 @@ module Puppet # 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 -%{# HEADER: This file was autogenerated at #{Time.now} by puppet. While it -# HEADER: can still be managed manually, it is definitely not recommended.\n} +%{# HEADER: This file was autogenerated at #{Time.now} +# HEADER: by puppet. While it can still be managed manually, it +# HEADER: is definitely not recommended.\n} end # Store a new instance of a host. Called from Host#initialize. @@ -160,20 +185,30 @@ module Puppet # we've set up our naming stuff correctly everywhere. # Mark found objects as present - Puppet.debug "Found %s %s" % [self.name, obj.name] obj.is = [:ensure, :present] + hash.each { |param, value| + if state = obj.state(param) + state.is = value + elsif val = obj[param] + obj[param] = val + else + # There is a value on disk, but it should go away + obj.is = [param, value] + obj[param] = :absent + end + } else # create a new obj, since no existing one seems to # match - obj = self.create( - :name => hash[:name] - ) or return false + obj = self.create(:name => hash[:name]) + + # We can't just pass the hash in at object creation time, + # because it sets the should value, not the is value. hash.delete(:name) + hash.each { |param, value| + obj.is = [param, value] + } end - - hash.each { |param, value| - obj.is = [param, value] - } end # Retrieve the text for the file. Returns nil in the unlikely @@ -205,14 +240,6 @@ module Puppet else @fileobj.write(self.to_file()) end - - #self.each { |obj| - # obj.each { |state| - # obj.notice "Changing from %s to %s" % - # [state.is.inspect, state.should.inspect] - # state.is = state.should - # } - #} end # Collect all Host instances convert them into literal text. @@ -223,9 +250,6 @@ module Puppet # Don't write out objects that should be absent if obj.is_a?(self) if obj.should(:ensure) == :absent - #obj.warning "removing; is = %s, should = %s" % - # [obj.is(:ensure).inspect, obj.should(:ensure).inspect] - #obj.is = [:ensure, :absent] true end end @@ -239,7 +263,7 @@ module Puppet return str else - Puppet.notice "No host instances" + Puppet.notice "No %s instances" % self.name return "" end end @@ -262,7 +286,8 @@ module Puppet state.is_a?(Puppet::State::ParsedParam) } - if state.is == :absent + # Unless we've retrieved, we don't know if we exist + if ! state.is or state.is == :absent return false else return true @@ -286,6 +311,24 @@ module Puppet def store self.class.store() end + + def value(name) + unless name.is_a? Symbol + name = name.intern + end + if @states.include? name + val = @states[name].value + if val == :absent + return nil + else + return val + end + elsif @parameters.include? name + return @parameters[name].value + else + return nil + end + end end end end diff --git a/lib/puppet/type/parsedtype/host.rb b/lib/puppet/type/parsedtype/host.rb index e70f2dfc1..6463232c1 100755 --- a/lib/puppet/type/parsedtype/host.rb +++ b/lib/puppet/type/parsedtype/host.rb @@ -5,6 +5,7 @@ require 'puppet/type/state' module Puppet newtype(:host, Puppet::Type::ParsedType) do + newstate(:ip) do desc "The host's IP address." end @@ -73,12 +74,6 @@ module Puppet @fields = [:ip, :name, :alias] @filetype = Puppet::FileType.filetype(:flat) -# case Facter["operatingsystem"].value -# when "Solaris": -# @filetype = Puppet::FileType::SunOS -# else -# @filetype = Puppet::CronType::Default -# end # Parse a host file # @@ -117,8 +112,6 @@ module Puppet hash.delete(:alias) end - Puppet.notice "sending %s" % hash.inspect - hash2obj(hash) hash.clear @@ -129,10 +122,10 @@ module Puppet # Convert the current object into a host-style string. def to_record - str = "%s\t%s" % [self.state(:ip).should, self[:name]] + str = "%s\t%s" % [self.state(:ip).value, self[:name]] - if state = self.state(:alias) - str += "\t%s" % state.should.join("\t") + if value = self.value(:alias) + str += "\t%s" % value.join("\t") end str diff --git a/lib/puppet/type/parsedtype/port.rb b/lib/puppet/type/parsedtype/port.rb index 52057d21c..369d2aea3 100755 --- a/lib/puppet/type/parsedtype/port.rb +++ b/lib/puppet/type/parsedtype/port.rb @@ -28,12 +28,22 @@ module Puppet # We actually want to return the whole array here, not just the first # value. def should - @should + if defined? @should + if @should[0] == :absent + return :absent + else + return @should + end + else + return nil + end end validate do |value| - unless value == "udp" or value == "tcp" - raise Puppet::Error, "Protocols can be either 'udp' or 'tcp'" + valids = ["udp", "tcp", "ddp", :absent] + unless valids.include? value + raise Puppet::Error, + "Protocols can be either 'udp' or 'tcp', not %s" % value end end end @@ -47,10 +57,10 @@ module Puppet end newstate(:alias) do - desc "Any aliases the port might have. Multiple values must be specified - as an array. Note that this state has the same name as one of the - metaparams; using this state to set aliases will make those aliases - available in your Puppet scripts and also on disk." + desc "Any aliases the port might have. Multiple values must be + specified as an array. Note that this state has the same name as + one of the metaparams; using this state to set aliases will make + those aliases available in your Puppet scripts and also on disk." # We have to override the feeding mechanism; it might be nil or # white-space separated @@ -71,18 +81,32 @@ module Puppet # We actually want to return the whole array here, not just the first # value. def should - @should + if defined? @should + if @should[0] == :absent + return :absent + else + return @should + end + else + return nil + end end validate do |value| - if value =~ /\s/ - raise Puppet::Error, "Aliases cannot have whitespace in them" + if value.is_a? String and value =~ /\s/ + raise Puppet::Error, + "Aliases cannot have whitespace in them: %s" % + value.inspect end end munge do |value| - # Add the :alias metaparam in addition to the state - @parent.newmetaparam(@parent.class.metaparamclass(:alias), value) + unless value == "absent" or value == :absent + # Add the :alias metaparam in addition to the state + @parent.newmetaparam( + @parent.class.metaparamclass(:alias), value + ) + end value end end @@ -101,12 +125,6 @@ module Puppet @fields = [:ip, :name, :alias] @filetype = Puppet::FileType.filetype(:flat) -# case Facter["operatingsystem"].value -# when "Solaris": -# @filetype = Puppet::FileType::SunOS -# else -# @filetype = Puppet::CronType::Default -# end # Parse a services file # @@ -122,10 +140,6 @@ module Puppet # add comments and blank lines to the list as they are @instances << line else - #if match = /^(\S+)\s+(\d+)\/(\w+)/.match(line) - # Puppet.warning "%s %s %s" % [$1, $2, $3] - # next - #if line.sub(/^(\S+)\s+(\d+)\/(\w+)\s*(\S*)$/.match(line) if line.sub!(/^(\S+)\s+(\d+)\/(\w+)\s*/, '') hash[:name] = $1 hash[:number] = $2 @@ -134,6 +148,9 @@ module Puppet unless line == "" line.sub!(/^([^#]+)\s*/) do |value| aliases = $1 + + # Remove any trailing whitespace + aliases.strip! unless aliases =~ /^\s*$/ hash[:alias] = aliases end @@ -175,6 +192,9 @@ module Puppet unless @states.include?(:protocols) return false end + + # This method is only called from parsing, so we only worry + # about 'is' values. proto = self.state(:protocols).is if proto.nil? or proto == :absent @@ -192,9 +212,7 @@ module Puppet unless proto.include?(hash[:protocols]) # We are missing their proto proto << hash[:protocols] - #Puppet.info "new proto is %s" % proto.inspect @states[:protocols].is = proto - #Puppet.info "new value is %s" % @states[:protocols].is.inspect end end @@ -206,20 +224,20 @@ module Puppet return true end - # Convert the current object into a host-style string. + # Convert the current object into one or more services entry. def to_record - self.state(:protocols).should.collect { |proto| - str = "%s\t%s/%s" % [self[:name], self.state(:number).should, + self.state(:protocols).value.collect { |proto| + str = "%s\t%s/%s" % [self[:name], self.value(:number), proto] - if state = self.state(:alias) - str += "\t%s" % state.should.join(" ") + if value = self.value(:alias) and value != :absent + str += "\t%s" % value.join(" ") else str += "\t" end - if state = self.state(:description) - str += "\t# %s" % state.should + if value = self.value(:description) and value != :absent + str += "\t# %s" % value else str += "\t" end diff --git a/lib/puppet/type/parsedtype/sshkey.rb b/lib/puppet/type/parsedtype/sshkey.rb index 641741233..c1a09bb11 100755 --- a/lib/puppet/type/parsedtype/sshkey.rb +++ b/lib/puppet/type/parsedtype/sshkey.rb @@ -27,7 +27,11 @@ module Puppet # We actually want to return the whole array here, not just the first # value. def should - @should + if defined? @should + return @should + else + return nil + end end validate do |value| @@ -119,9 +123,9 @@ module Puppet def to_record name = self[:name] if @states.include?(:alias) - name += "," + @states[:alias].should.join(",") + name += "," + @states[:alias].value.join(",") end - [name, @states[:type].should, @states[:key].should].join(" ") + [name, @states[:type].value, @states[:key].value].join(" ") end end end diff --git a/lib/puppet/type/state.rb b/lib/puppet/type/state.rb index 377e84a65..f090f38ec 100644 --- a/lib/puppet/type/state.rb +++ b/lib/puppet/type/state.rb @@ -39,42 +39,6 @@ class State < Puppet::Parameter define_method("set_" + name.to_s, &block) end -# -# def self.aliasvalue(name, other) -# @statevalues ||= {} -# unless @statevalues.include?(other) -# raise Puppet::DevError, "Cannot alias nonexistent value %s" % other -# end -# -# @aliasvalues ||= {} -# @aliasvalues[name] = other -# end -# -# def self.alias(name) -# @aliasvalues[name] -# end -# - def self.defaultvalues - newvalue(:present) do - @parent.create - end - - newvalue(:absent) do - @parent.destroy - end - - # This doc will probably get overridden - @doc ||= "The basic state that the object should be in." - end -# -# # Return the list of valid values. -# def self.values -# @statevalues ||= {} -# @aliasvalues ||= {} -# -# #[@aliasvalues.keys, @statevalues.keys].flatten -# @statevalues.keys -# end # Call the method associated with a given value. def set @@ -278,46 +242,13 @@ class State < Puppet::Parameter self.set end -# munge do |value| -# if self.class.values.empty? -# # This state isn't using defined values to do its work. -# return value -# end -# intern = value.to_s.intern -# # If it's a valid value, always return it as a symbol. -# if self.class.values.include?(intern) -# retval = intern -# elsif other = self.class.alias(intern) -# self.info "returning alias %s for %s" % [other, intern] -# retval = other -# else -# retval = value -# end -# retval -# end -# -# # Verify that the passed value is valid. -# validate do |value| -# if self.class.values.empty? -# # This state isn't using defined values to do its work. -# return -# end -# unless value.is_a?(Symbol) -# value = value.to_s.intern -# end -# unless self.class.values.include?(value) or self.class.alias(value) -# self.fail "Invalid '%s' value '%s'. Valid values are '%s'" % -# [self.class.name, value, self.class.values.join(", ")] -# end -# end - # How should a state change be printed as a string? def change_to_s begin if @is == :absent return "defined '%s' as '%s'" % [self.name, self.should_to_s] - elsif self.should == :absent + elsif self.should == :absent or self.should == [:absent] return "undefined %s from '%s'" % [self.name, self.is_to_s] else @@ -341,7 +272,11 @@ class State < Puppet::Parameter end def should_to_s - @should.join(" ") + if defined? @should + @should.join(" ") + else + return nil + end end def to_s @@ -349,10 +284,23 @@ class State < Puppet::Parameter end # This state will get automatically added to any type that responds - # to the methods 'exists?', 'create', and 'remove'. + # to the methods 'exists?', 'create', and 'destroy'. class Ensure < Puppet::State @name = :ensure + def self.defaultvalues + newvalue(:present) do + @parent.create + end + + newvalue(:absent) do + @parent.destroy + end + + # This doc will probably get overridden + @doc ||= "The basic state that the object should be in." + end + def self.inherited(sub) # Add in the two states that everyone will have. sub.class_eval do @@ -378,6 +326,11 @@ class State < Puppet::Parameter end def retrieve + # XXX This is a problem -- whether the object exists or not often + # depends on the results of other states, yet we're the first state + # to get checked, which means that those other states do not have + # @is values set. This seems to be the source of quite a few bugs, + # although they're mostly logging bugs, not functional ones. if @parent.exists? @is = :present else |