Paired-With: Max Martin
Reviewed-By: Jacob Helwig

Signed-off-by: Nick Lewis <[email protected]>
---
 .../indirector/facts/inventory_active_record.rb    |   34 +++++++++++++
 lib/puppet/rails/inventory_host.rb                 |   26 ++++++++++
 .../facts/inventory_active_record_spec.rb          |   52 ++++++++++++++++++++
 3 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/lib/puppet/indirector/facts/inventory_active_record.rb 
b/lib/puppet/indirector/facts/inventory_active_record.rb
index 6cd63ab..30cb88e 100644
--- a/lib/puppet/indirector/facts/inventory_active_record.rb
+++ b/lib/puppet/indirector/facts/inventory_active_record.rb
@@ -30,4 +30,38 @@ class Puppet::Node::Facts::InventoryActiveRecord < 
Puppet::Indirector::ActiveRec
       host.save
     end
   end
+
+  def search(request)
+    return [] unless request.options
+    fact_names = []
+    filters = Hash.new {|h,k| h[k] = []}
+    request.options.each do |key,value|
+      type, name, operator = key.to_s.split(".")
+      operator ||= "eq"
+      filters[operator] << [name,value]
+    end
+
+
+    host_sets = []
+    filters['eq'].each do |name,value|
+      host_sets << 
Puppet::Rails::InventoryHost.has_fact_with_value(name,value).map {|host| 
host.name}
+    end
+    filters['ne'].each do |name,value|
+      host_sets << 
Puppet::Rails::InventoryHost.has_fact_without_value(name,value).map {|host| 
host.name}
+    end
+    {
+      'gt' => '>',
+      'lt' => '<',
+      'ge' => '>=',
+      'le' => '<='
+    }.each do |operator_name,operator|
+      filters[operator_name].each do |name,value|
+        hosts_with_fact = Puppet::Rails::InventoryHost.has_fact(name)
+        host_sets << hosts_with_fact.select {|h| 
h.value_for(name).to_f.send(operator, value.to_f)}.map {|host| host.name}
+      end
+    end
+
+    # to_a because [].inject == nil
+    host_sets.inject {|hosts,this_set| hosts & this_set}.to_a
+  end
 end
diff --git a/lib/puppet/rails/inventory_host.rb 
b/lib/puppet/rails/inventory_host.rb
index 433e543..10dd620 100644
--- a/lib/puppet/rails/inventory_host.rb
+++ b/lib/puppet/rails/inventory_host.rb
@@ -3,6 +3,32 @@ require 'puppet/rails/inventory_fact'
 class Puppet::Rails::InventoryHost < ::ActiveRecord::Base
   has_many :facts, :class_name => "Puppet::Rails::InventoryFact", :dependent 
=> :delete_all
 
+  named_scope :has_fact_with_value, lambda { |name,value|
+    {
+      :conditions => ["inventory_facts.name = ? AND inventory_facts.value = 
?", name, value],
+      :joins => :facts
+    }
+  }
+
+  named_scope :has_fact_without_value, lambda { |name,value|
+    {
+      :conditions => ["inventory_facts.name = ? AND inventory_facts.value != 
?", name, value],
+      :joins => :facts
+    }
+  }
+
+  named_scope :has_fact, lambda { |name|
+    {
+      :conditions => ["inventory_facts.name = ?", name],
+      :joins => :facts
+    }
+  }
+
+  def value_for(fact_name)
+    fact = facts.find_by_name(fact_name)
+    fact ? fact.value : nil
+  end
+
   def facts_to_hash
     facts.inject({}) do |fact_hash,fact|
       fact_hash.merge(fact.name => fact.value)
diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb 
b/spec/unit/indirector/facts/inventory_active_record_spec.rb
index b97bada..7fb5556 100644
--- a/spec/unit/indirector/facts/inventory_active_record_spec.rb
+++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb
@@ -95,5 +95,57 @@ describe "Puppet::Node::Facts::InventoryActiveRecord", :if 
=> (Puppet.features.r
       Puppet::Node::Facts.find("array").values["fact1"].should == "value1"
     end
   end
+
+  describe "#search" do
+
+    it "should return node names that match 'equal' constraints" do
+      Puppet::Node::Facts.new("foo", "fact1" => "value1", "fact2" => "value2", 
"fact3" => "value3").save
+      Puppet::Node::Facts.new("bar", "fact1" => "value2").save
+      Puppet::Node::Facts.new("baz", "fact1" => "value1", "fact2" => "value1", 
"fact3" => "value1").save
+
+      request = Puppet::Indirector::Request.new(:facts, :search, nil,
+                                                {'facts.fact1.eq' => 'value1',
+                                                 'facts.fact2.eq' => 'value2',
+                                                 'facts.fact3.eq' => 'value3'})
+      terminus.search(request).should =~ ["foo"]
+    end
+
+    it "should return node names that match 'not equal' constraints" do
+      Puppet::Node::Facts.new("foo", "fact1" => "value1", "fact2" => "value2", 
"fact3" => "value3").save
+      Puppet::Node::Facts.new("bar", "fact1" => "value2").save
+      Puppet::Node::Facts.new("baz", "fact1" => "value1", "fact2" => "value1", 
"fact3" => "value1").save
+      Puppet::Node::Facts.new("bang", "fact1" => "value1", "fact2" => 
"value2", "fact3" => "value1").save
+
+      request = Puppet::Indirector::Request.new(:facts, :search, nil,
+                                                {'facts.fact1.ne' => 'value3',
+                                                 'facts.fact2.ne' => 'value1',
+                                                 'facts.fact3.ne' => 'value2'})
+      terminus.search(request).should =~ ["foo","bang"]
+    end
+
+    it "should return node names that match strict inequality constraints" do
+      Puppet::Node::Facts.new("foo", "uptime_days" => "30").save
+      Puppet::Node::Facts.new("bar", "uptime_days" => "60").save
+      Puppet::Node::Facts.new("baz", "uptime_days" => "90").save
+
+      request = Puppet::Indirector::Request.new(:facts, :search, nil,
+                                                {'facts.uptime_days.gt' => 
'20',
+                                                 'facts.uptime_days.lt' => 
'70'})
+
+      terminus.search(request).should =~ ["foo","bar"]
+    end
+
+    it "should return node names that match non-strict inequality constraints" 
do
+      Puppet::Node::Facts.new("foo", "uptime_days" => "30").save
+      Puppet::Node::Facts.new("bar", "uptime_days" => "60").save
+      Puppet::Node::Facts.new("baz", "uptime_days" => "90").save
+
+      request = Puppet::Indirector::Request.new(:facts, :search, nil,
+                                                {'facts.uptime_days.ge' => 
'30',
+                                                 'facts.uptime_days.le' => 
'60'})
+
+      terminus.search(request).should =~ ["foo","bar"]
+    end
+  end
 end
 
-- 
1.7.4.1

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to