This is most of the way to replacing standard StoreConfigs
integration with the Indirector.  We still need to convert
the Catalog and then change all of the integraiton points
(which is mostly the 'store' call in the Compiler).

Signed-off-by: Luke Kanies <[email protected]>
---
 lib/puppet/indirector/active_record.rb       |   28 +++++++
 lib/puppet/indirector/facts/active_record.rb |   35 +++++++++
 lib/puppet/indirector/node/active_record.rb  |    7 ++
 lib/puppet/rails/host.rb                     |   26 ++++++-
 spec/unit/indirector/active_record.rb        |   75 +++++++++++++++++++
 spec/unit/indirector/facts/active_record.rb  |  103 ++++++++++++++++++++++++++
 spec/unit/indirector/node/active_record.rb   |   18 +++++
 spec/unit/rails/host.rb                      |   91 +++++++++++++++++++++++
 8 files changed, 382 insertions(+), 1 deletions(-)
 create mode 100644 lib/puppet/indirector/active_record.rb
 create mode 100644 lib/puppet/indirector/facts/active_record.rb
 create mode 100644 lib/puppet/indirector/node/active_record.rb
 create mode 100755 spec/unit/indirector/active_record.rb
 create mode 100755 spec/unit/indirector/facts/active_record.rb
 create mode 100755 spec/unit/indirector/node/active_record.rb
 create mode 100755 spec/unit/rails/host.rb

diff --git a/lib/puppet/indirector/active_record.rb 
b/lib/puppet/indirector/active_record.rb
new file mode 100644
index 0000000..531109a
--- /dev/null
+++ b/lib/puppet/indirector/active_record.rb
@@ -0,0 +1,28 @@
+require 'puppet/indirector'
+
+class Puppet::Indirector::ActiveRecord < Puppet::Indirector::Terminus
+    class << self
+        attr_accessor :ar_model
+    end
+
+    def self.use_ar_model(klass)
+        self.ar_model = klass
+    end
+
+    def ar_model
+        self.class.ar_model
+    end
+
+    def initialize
+        Puppet::Rails.init
+    end
+
+    def find(request)
+        return nil unless instance = ar_model.find_by_name(request.key)
+        instance.to_puppet
+    end
+
+    def save(request)
+        ar_model.from_puppet(request.instance).save
+    end
+end
diff --git a/lib/puppet/indirector/facts/active_record.rb 
b/lib/puppet/indirector/facts/active_record.rb
new file mode 100644
index 0000000..5fb2596
--- /dev/null
+++ b/lib/puppet/indirector/facts/active_record.rb
@@ -0,0 +1,35 @@
+require 'puppet/rails/fact_name'
+require 'puppet/rails/fact_value'
+require 'puppet/indirector/active_record'
+
+class Puppet::Node::Facts::ActiveRecord < Puppet::Indirector::ActiveRecord
+    use_ar_model Puppet::Rails::Host
+
+    # Find the Rails host and pull its facts as a Facts instance.
+    def find(request)
+        return nil unless host = ar_model.find_by_name(request.key, :include 
=> {:fact_values => :fact_name})
+
+        facts = Puppet::Node::Facts.new(host.name)
+        facts.values = host.get_facts_hash.inject({}) do |hash, ary|
+            # Convert all single-member arrays into plain values.
+            param = ary[0]
+            values = ary[1].collect { |v| v.value }
+            values = values[0] if values.length == 1
+            hash[param] = values
+            hash
+        end
+
+        facts
+    end
+
+    # Save the values from a Facts instance as the facts on a Rails Host 
instance.
+    def save(request)
+        facts = request.instance
+
+        host = ar_model.find_by_name(facts.name) || ar_model.create(:name => 
facts.name)
+        
+        host.setfacts(facts.values)
+
+        host.save
+    end
+end
diff --git a/lib/puppet/indirector/node/active_record.rb 
b/lib/puppet/indirector/node/active_record.rb
new file mode 100644
index 0000000..ab33af4
--- /dev/null
+++ b/lib/puppet/indirector/node/active_record.rb
@@ -0,0 +1,7 @@
+require 'puppet/rails/host'
+require 'puppet/indirector/active_record'
+require 'puppet/node'
+
+class Puppet::Node::ActiveRecord < Puppet::Indirector::ActiveRecord
+    use_ar_model Puppet::Rails::Host
+end
diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb
index 851cc21..23a2255 100644
--- a/lib/puppet/rails/host.rb
+++ b/lib/puppet/rails/host.rb
@@ -22,6 +22,18 @@ class Puppet::Rails::Host < ActiveRecord::Base
         end
     end
 
+    def self.from_puppet(node)
+        host = find_by_name(node.name) || new(:name => node.name)
+
+        {"ipaddress" => "ip", "environment" => "environment"}.each do 
|myparam, itsparam|
+            if value = node.send(myparam)
+                host.send(itsparam + "=", value)
+            end
+        end
+
+        host
+    end
+
     # Store our host in the database.
     def self.store(node, resources)
         args = {}
@@ -70,6 +82,8 @@ class Puppet::Rails::Host < ActiveRecord::Base
     end
     
     # returns a hash of fact_names.name => [ fact_values ] for this host.
+    # Note that 'fact_values' is actually a list of the value instances, not
+    # just actual values.
     def get_facts_hash
         fact_values = self.fact_values.find(:all, :include => :fact_name)
         return fact_values.inject({}) do | hash, value |
@@ -202,5 +216,15 @@ class Puppet::Rails::Host < ActiveRecord::Base
         self.last_connect = Time.now
         save
     end
-end
 
+    def to_puppet
+        node = Puppet::Node.new(self.name)
+        {"ip" => "ipaddress", "environment" => "environment"}.each do 
|myparam, itsparam|
+            if value = send(myparam)
+                node.send(itsparam + "=", value)
+            end
+        end
+
+        node
+    end
+end
diff --git a/spec/unit/indirector/active_record.rb 
b/spec/unit/indirector/active_record.rb
new file mode 100755
index 0000000..6d81b0f
--- /dev/null
+++ b/spec/unit/indirector/active_record.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+require 'puppet/indirector/active_record'
+
+describe Puppet::Indirector::ActiveRecord do
+    before do
+        Puppet::Rails.stubs(:init)
+
+        Puppet::Indirector::Terminus.stubs(:register_terminus_class)
+        @model = mock 'model'
+        @indirection = stub 'indirection', :name => :mystuff, 
:register_terminus_type => nil, :model => @model
+        Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
+
+        @active_record_class = Class.new(Puppet::Indirector::ActiveRecord) do
+            def self.to_s
+                "Mystuff::Testing"
+            end
+        end
+
+        @ar_model = mock 'ar_model'
+
+        @active_record_class.use_ar_model @ar_model
+        @terminus = @active_record_class.new
+
+        @name = "me"
+        @instance = stub 'instance', :name => @name
+
+        @request = stub 'request', :key => @name, :instance => @instance
+    end
+
+    it "should allow declaration of an ActiveRecord model to use" do
+        @active_record_class.use_ar_model "foo"
+        @active_record_class.ar_model.should == "foo"
+    end
+
+    describe "when initializing" do
+        it "should init Rails" do
+            Puppet::Rails.expects(:init)
+            @active_record_class.new
+        end
+    end
+
+    describe "when finding an instance" do
+        it "should use the ActiveRecord model to find the instance" do
+            @ar_model.expects(:find_by_name).with(@name)
+
+            @terminus.find(@request)
+        end
+        
+        it "should return nil if no instance is found" do
+            @ar_model.expects(:find_by_name).with(@name).returns nil
+            @terminus.find(@request).should be_nil
+        end
+
+        it "should convert the instance to a Puppet object if it is found" do
+            instance = mock 'rails_instance'
+            instance.expects(:to_puppet).returns "mypuppet"
+
+            @ar_model.expects(:find_by_name).with(@name).returns instance
+            @terminus.find(@request).should == "mypuppet"
+        end
+    end
+
+    describe "when saving an instance" do
+        it "should use the ActiveRecord model to convert the instance into a 
Rails object and then save that rails object" do
+            rails_object = mock 'rails_object'
+            @ar_model.expects(:from_puppet).with(@instance).returns 
rails_object
+
+            rails_object.expects(:save)
+
+            @terminus.save(@request)
+        end
+    end
+end
diff --git a/spec/unit/indirector/facts/active_record.rb 
b/spec/unit/indirector/facts/active_record.rb
new file mode 100755
index 0000000..340f2cf
--- /dev/null
+++ b/spec/unit/indirector/facts/active_record.rb
@@ -0,0 +1,103 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/node/facts'
+require 'puppet/indirector/facts/active_record'
+
+describe Puppet::Node::Facts::ActiveRecord do
+    confine "Missing Rails" => Puppet.features.rails?
+
+    before do
+        Puppet.features.stubs(:rails?).returns true
+        @terminus = Puppet::Node::Facts::ActiveRecord.new
+    end
+
+    it "should be a subclass of the ActiveRecord terminus class" do
+        Puppet::Node::Facts::ActiveRecord.ancestors.should 
be_include(Puppet::Indirector::ActiveRecord)
+    end
+
+    it "should use Puppet::Rails::Host as its ActiveRecord model" do
+        Puppet::Node::Facts::ActiveRecord.ar_model.should 
equal(Puppet::Rails::Host)
+    end
+
+    describe "when finding an instance" do
+        before do
+            @request = stub 'request', :key => "foo"
+        end
+
+        it "should use the Hosts ActiveRecord class to find the host" do
+            Puppet::Rails::Host.expects(:find_by_name).with { |key, args| key 
== "foo" }
+            @terminus.find(@request)
+        end
+
+        it "should include the fact names and values when finding the host" do
+            Puppet::Rails::Host.expects(:find_by_name).with { |key, args| 
args[:include] == {:fact_values => :fact_name} }
+            @terminus.find(@request)
+        end
+
+        it "should return nil if no host instance can be found" do
+            Puppet::Rails::Host.expects(:find_by_name).returns nil
+
+            @terminus.find(@request).should be_nil
+        end
+
+        it "should convert the node's parameters into a Facts instance if a 
host instance is found" do
+            host = stub 'host', :name => "foo"
+            host.expects(:get_facts_hash).returns("one" => [mock("two_value", 
:value => "two")], "three" => [mock("three_value", :value => "four")])
+
+            Puppet::Rails::Host.expects(:find_by_name).returns host
+
+            result = @terminus.find(@request)
+
+            result.should be_instance_of(Puppet::Node::Facts)
+            result.name.should == "foo"
+            result.values.should == {"one" => "two", "three" => "four"}
+        end
+
+        it "should convert all single-member arrays into non-arrays" do
+            host = stub 'host', :name => "foo"
+            host.expects(:get_facts_hash).returns("one" => [mock("two_value", 
:value => "two")])
+
+            Puppet::Rails::Host.expects(:find_by_name).returns host
+
+            @terminus.find(@request).values["one"].should == "two"
+        end
+    end
+
+    describe "when saving an instance" do
+        before do
+            @host = stub 'host', :name => "foo", :save => nil, :setfacts => nil
+            Puppet::Rails::Host.stubs(:find_by_name).returns @host
+            @facts = Puppet::Node::Facts.new("foo", "one" => "two", "three" => 
"four")
+            @request = stub 'request', :key => "foo", :instance => @facts
+        end
+
+        it "should find the Rails host with the same name" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns 
@host
+
+            @terminus.save(@request)
+        end
+
+        it "should create a new Rails host if none can be found" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns nil
+
+            Puppet::Rails::Host.expects(:create).with(:name => "foo").returns 
@host
+
+            @terminus.save(@request)
+        end
+
+        it "should set the facts as facts on the Rails host instance" do
+            # There is other stuff added to the hash.
+            @host.expects(:setfacts).with { |args| args["one"] == "two" and 
args["three"] == "four" }
+
+            @terminus.save(@request)
+        end
+
+        it "should save the Rails host instance" do
+            @host.expects(:save)
+
+            @terminus.save(@request)
+        end
+    end
+end
diff --git a/spec/unit/indirector/node/active_record.rb 
b/spec/unit/indirector/node/active_record.rb
new file mode 100755
index 0000000..22a6beb
--- /dev/null
+++ b/spec/unit/indirector/node/active_record.rb
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/node'
+require 'puppet/indirector/node/active_record'
+
+describe Puppet::Node::ActiveRecord do
+    confine "Missing Rails" => Puppet.features.rails?
+
+    it "should be a subclass of the ActiveRecord terminus class" do
+        Puppet::Node::ActiveRecord.ancestors.should 
be_include(Puppet::Indirector::ActiveRecord)
+    end
+
+    it "should use Puppet::Rails::Host as its ActiveRecord model" do
+        Puppet::Node::ActiveRecord.ar_model.should equal(Puppet::Rails::Host)
+    end
+end
diff --git a/spec/unit/rails/host.rb b/spec/unit/rails/host.rb
new file mode 100755
index 0000000..882abbd
--- /dev/null
+++ b/spec/unit/rails/host.rb
@@ -0,0 +1,91 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe "Puppet::Rails::Host" do
+    confine "Cannot test without ActiveRecord" => Puppet.features.rails?
+
+    def column(name, type)
+        ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false)
+    end
+
+    before do
+        require 'puppet/rails/host'
+
+        # Stub this so we don't need access to the DB.
+        Puppet::Rails::Host.stubs(:columns).returns([column("name", "string"), 
column("environment", "string"), column("ip", "string")])
+
+        @node = Puppet::Node.new("foo")
+        @node.environment = "production"
+        @node.ipaddress = "127.0.0.1"
+
+        @host = stub 'host', :environment= => nil, :ip= => nil
+    end
+
+    describe "when converting a Puppet::Node instance into a Rails instance" do
+        it "should modify any existing instance in the database" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns 
@host
+
+            Puppet::Rails::Host.from_puppet(@node)
+        end
+
+        it "should create a new instance in the database if none can be found" 
do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns nil
+            Puppet::Rails::Host.expects(:new).with(:name => "foo").returns 
@host
+
+            Puppet::Rails::Host.from_puppet(@node)
+        end
+
+        it "should copy the environment from the Puppet instance" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns 
@host
+
+            @node.environment = "production"
+            @host.expects(:environment=).with "production"
+
+            Puppet::Rails::Host.from_puppet(@node)
+        end
+
+        it "should copy the ipaddress from the Puppet instance" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns 
@host
+
+            @node.ipaddress = "192.168.0.1"
+            @host.expects(:ip=).with "192.168.0.1"
+
+            Puppet::Rails::Host.from_puppet(@node)
+        end
+
+        it "should not save the Rails instance" do
+            Puppet::Rails::Host.expects(:find_by_name).with("foo").returns 
@host
+
+            @host.expects(:save).never
+
+            Puppet::Rails::Host.from_puppet(@node)
+        end
+    end
+
+    describe "when converting a Puppet::Rails::Host instance into a 
Puppet::Node instance" do
+        before do
+            @host = Puppet::Rails::Host.new(:name => "foo", :environment => 
"production", :ip => "127.0.0.1")
+            @node = Puppet::Node.new("foo")
+            Puppet::Node.stubs(:new).with("foo").returns @node
+        end
+
+        it "should create a new instance with the correct name" do
+            Puppet::Node.expects(:new).with("foo").returns @node
+
+            @host.to_puppet
+        end
+
+        it "should copy the environment from the Rails instance" do
+            @host.environment = "prod"
+            @node.expects(:environment=).with "prod"
+            @host.to_puppet
+        end
+
+        it "should copy the ipaddress from the Rails instance" do
+            @host.ip = "192.168.0.1"
+            @node.expects(:ipaddress=).with "192.168.0.1"
+            @host.to_puppet
+        end
+    end
+end
-- 
1.6.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