summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/indirector/active_record.rb28
-rw-r--r--lib/puppet/indirector/facts/active_record.rb35
-rw-r--r--lib/puppet/indirector/node/active_record.rb7
-rw-r--r--lib/puppet/rails/host.rb26
-rwxr-xr-xspec/unit/indirector/active_record.rb75
-rwxr-xr-xspec/unit/indirector/facts/active_record.rb103
-rwxr-xr-xspec/unit/indirector/node/active_record.rb18
-rwxr-xr-xspec/unit/rails/host.rb91
8 files changed, 382 insertions, 1 deletions
diff --git a/lib/puppet/indirector/active_record.rb b/lib/puppet/indirector/active_record.rb
new file mode 100644
index 000000000..531109a18
--- /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 000000000..5fb2596d7
--- /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 000000000..ab33af4b0
--- /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 851cc21d9..23a22553d 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 000000000..6d81b0fbe
--- /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 000000000..340f2cf4c
--- /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 000000000..22a6bebaf
--- /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 000000000..882abbd5a
--- /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