diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index de60cb170..bb1cd3947 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -1,223 +1,218 @@ # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::Collector attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :overrides, :collected - # Call the collection method, mark all of the returned objects as non-virtual, - # optionally applying parameter overrides. The collector can also delete himself - # from the compiler if there is no more resources to collect (valid only for resource fixed-set collector - # which get their resources from +collect_resources+ and not from the catalog) + # Call the collection method, mark all of the returned objects as + # non-virtual, optionally applying parameter overrides. The collector can + # also delete himself from the compiler if there is no more resources to + # collect (valid only for resource fixed-set collector which get their + # resources from +collect_resources+ and not from the catalog) def evaluate # Shortcut if we're not using storeconfigs and they're trying to collect # exported resources. if form == :exported and Puppet[:storeconfigs] != true Puppet.warning "Not collecting exported resources without storeconfigs" return false end if self.resources unless objects = collect_resources and ! objects.empty? return false end else method = "collect_#{@form.to_s}" objects = send(method).each do |obj| obj.virtual = false end return false if objects.empty? end # we have an override for the collected resources if @overrides and !objects.empty? - # force the resource to be always child of any other resource overrides[:source].meta_def(:child_of?) do true end # tell the compiler we have some override for him unless we already # overrided those resources objects.each do |res| unless @collected.include?(res.ref) - - newres = Puppet::Parser::Resource.new( - res.type, res.title, - :parameters => overrides[:parameters], - :file => overrides[:file], - :line => overrides[:line], - :source => overrides[:source], - - :scope => overrides[:scope] - ) + newres = Puppet::Parser::Resource. + new(res.type, res.title, + :parameters => overrides[:parameters], + :file => overrides[:file], + :line => overrides[:line], + :source => overrides[:source], + :scope => overrides[:scope]) scope.compiler.add_override(newres) end end end - # filter out object that already have been collected by ourself + # filter out object that this collector has previously found. objects.reject! { |o| @collected.include?(o.ref) } return false if objects.empty? # keep an eye on the resources we have collected objects.inject(@collected) { |c,o| c[o.ref]=o; c } # return our newly collected resources objects end def initialize(scope, type, equery, vquery, form) @scope = scope # initialisation @collected = {} # Canonize the type @type = Puppet::Resource.new(type, "whatever").type @equery = equery @vquery = vquery raise(ArgumentError, "Invalid query form #{form}") unless [:exported, :virtual].include?(form) @form = form end # add a resource override to the soon to be exported/realized resources def add_override(hash) raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters] # schedule an override for an upcoming collection @overrides = hash end private # Create our active record query. def build_active_record_query Puppet::Rails.init unless ActiveRecord::Base.connected? raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host host = Puppet::Rails::Host.find_by_name(@scope.host) search = "(exported=? AND restype=?)" values = [true, @type] search += " AND (#{@equery})" if @equery - # note: - # we're not eagerly including any relations here because - # it can creates so much objects we'll throw out later. - # We used to eagerly include param_names/values but the way - # the search filter is built ruined those efforts and we - # were eagerly loading only the searched parameter and not - # the other ones. + # note: we're not eagerly including any relations here because it can + # creates so much objects we'll throw out later. We used to eagerly + # include param_names/values but the way the search filter is built ruined + # those efforts and we were eagerly loading only the searched parameter + # and not the other ones. query = {} case search when /puppet_tags/ query = {:joins => {:resource_tags => :puppet_tag}} when /param_name/ query = {:joins => {:param_values => :param_name}} end # We're going to collect objects from rails, but we don't want any # objects from this host. search = ("host_id != ? AND #{search}") and values.unshift(host.id) if host query[:conditions] = [search, *values] query end # Collect exported objects. def collect_exported # First get everything from the export table. Just reuse our # collect_virtual method but tell it to use 'exported? for the test. resources = collect_virtual(true).reject { |r| ! r.virtual? } count = resources.length query = build_active_record_query # Now look them up in the rails db. When we support attribute comparison # and such, we'll need to vary the conditions, but this works with no # attributes, anyway. time = Puppet::Util.thinmark do Puppet::Rails::Resource.find(:all, query).each do |obj| if resource = exported_resource(obj) count += 1 resources << resource end end end scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time]) resources end def collect_resources @resources = [@resources] unless @resources.is_a?(Array) method = "collect_#{form.to_s}_resources" send(method) end def collect_exported_resources raise Puppet::ParseError, "realize() is not yet implemented for exported resources" end # Collect resources directly; this is the result of using 'realize', # which specifies resources, rather than using a normal collection. def collect_virtual_resources return [] unless defined?(@resources) and ! @resources.empty? result = @resources.dup.collect do |ref| if res = @scope.findresource(ref.to_s) @resources.delete(ref) res end end.reject { |r| r.nil? }.each do |res| res.virtual = false end # If there are no more resources to find, delete this from the list # of collections. @scope.compiler.delete_collection(self) if @resources.empty? result end # Collect just virtual objects, from our local compiler. def collect_virtual(exported = false) scope.compiler.resources.find_all do |resource| resource.type == @type and (exported ? resource.exported? : true) and match?(resource) end end # Seek a specific exported resource. def exported_resource(obj) if existing = @scope.findresource(obj.restype, obj.title) # Next see if we've already collected this resource return nil if existing.rails_id == obj.id # This is the one we've already collected raise Puppet::ParseError, "Exported resource #{obj.ref} cannot override local resource" end resource = obj.to_resource(self.scope) resource.exported = false scope.compiler.add_resource(scope, resource) resource end # Does the resource match our tests? We don't yet support tests, # so it's always true at the moment. def match?(resource) if self.vquery return self.vquery.call(resource) else return true end end end