[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.5-639-g8f94f35

test branch puppet-dev at googlegroups.com
Wed Jul 14 10:34:43 UTC 2010


The following commit has been merged in the upstream branch:
commit 432db2593f15de200767ec16c14f433f718a44d9
Author: Rein Henrichs <rein at puppetlabs.com>
Date:   Mon Jun 14 16:40:38 2010 -0700

    [#4055] Add CouchDB terminus for facts
    
    Implements an abstract CouchDB terminus and a concrete CouchDB terminus
    used to store node facts. Node facts are stored in a "node" document as
    the "facts" attribute. This node document may also be used by other
    couchdb termini that store node-related information. It is recommended
    to use a separate document (or documents) to store large data structures
    like catalogs, linking them to their related node document using
    embedded ids.
    
    This implementation depends on the "couchrest" gem.
    
    * Add Puppet.features.couchdb?
    * Add Puppet[:couchdb_url] setting
    * Add Puppet::Node::Facts#== for testing
    * Add PuppetSpec::FIXTURE_DIR for easy access to fixture files
    * Add CouchDB Terminus
    * Add Facts::CouchDB terminus
      * Stores facts inside a "node" document
      * Use key (hostname) as _id for node document
      * #find returns nil if document cannot be found
      * #save finds and updates existing document OR creates new doc  [1]
      * Store facts in "facts" attribute of node document

diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 78f4cd5..9de73f5 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -680,6 +680,10 @@ module Puppet
             and other environments normally use ``debug``."]
     )
 
+    setdefaults(:couchdb,
+        :couchdb_url => ["http://127.0.0.1:5984/puppet", "The url where the puppet couchdb database will be created"]
+    )
+
     setdefaults(:transaction,
         :tags => ["", "Tags to use to find resources.  If this is set, then
             only resources tagged with the specified tags will be applied.
diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb
index 8a21fd3..0ca408c 100644
--- a/lib/puppet/feature/base.rb
+++ b/lib/puppet/feature/base.rb
@@ -45,3 +45,6 @@ end
 Puppet.features.add(:win32, :libs => ["sys/admin", "win32/process", "win32/dir"])
 
 raise Puppet::Error "Cannot determine basic system flavour" unless Puppet.features.posix? or Puppet.features.win32?
+
+# We have CouchDB
+Puppet.features.add(:couchdb, :libs => ["couchrest"])
diff --git a/lib/puppet/indirector/couch.rb b/lib/puppet/indirector/couch.rb
new file mode 100644
index 0000000..b328f5c
--- /dev/null
+++ b/lib/puppet/indirector/couch.rb
@@ -0,0 +1,68 @@
+require 'couchrest'
+class Puppet::Indirector::Couch < Puppet::Indirector::Terminus
+
+    # The CouchRest database instance. One database instance per Puppet runtime
+    # should be sufficient.
+    #
+    def self.db
+        @db ||= CouchRest.database! Puppet[:couchdb_url]
+    end
+
+    def db; self.class.db end
+
+    def find(request)
+        attributes_of db.get(id_for(request))
+    rescue RestClient::ResourceNotFound
+        Puppet.debug "No couchdb document with id: #{id_for(request)}"
+        return nil
+    end
+
+    # Create or update the couchdb document with the request's data hash.
+    #
+    # RKH:TODO: Do not depend on error handling, check if the document exists
+    # first. (Does couchrest support this?)
+    #
+    def save(request)
+        raise ArgumentError, "PUT does not accept options" unless request.options.empty?
+
+        # Try to find an existing document.
+        doc = db.get(id_for(request))
+        doc.merge(hash_from(request))
+        doc.save
+    rescue RestClient::ResourceNotFound
+        # Document does not yet exist, create it
+        db.save_doc hash_from(request)
+    end
+
+    private
+
+    # The attributes hash that is serialized to CouchDB as JSON. It includes
+    # metadata that is used to help aggregate data in couchdb. Add
+    # model-specific attributes in subclasses.
+    #
+    def hash_from(request)
+        {
+            "_id"         => id_for(request),
+            "puppet_type" => document_type_for(request)
+        }
+    end
+
+    # The couchdb response stripped of metadata, used to instantiate the model
+    # instance that is returned by save.
+    #
+    def attributes_of(response)
+        response.reject{|k,v| k =~ /^(_rev|puppet_)/ }
+    end
+
+    def document_type_for(request)
+        request.indirection_name
+    end
+
+    # The id used to store the object in couchdb. Implemented in subclasses.
+    #
+    def id_for(request)
+        raise NotImplementedError
+    end
+
+end
+
diff --git a/lib/puppet/indirector/facts/couch.rb b/lib/puppet/indirector/facts/couch.rb
new file mode 100644
index 0000000..522fe33
--- /dev/null
+++ b/lib/puppet/indirector/facts/couch.rb
@@ -0,0 +1,31 @@
+require 'puppet/node/facts'
+require 'puppet/indirector/couch'
+class Puppet::Node::Facts::Couch < Puppet::Indirector::Couch
+
+    # Return the facts object or nil if there is no document
+    def find(request)
+        doc = super
+        doc ? model.new(doc['_id'], doc['facts']) : nil
+    end
+
+    private
+
+    # Facts values are stored to the document's 'facts' attribute. Hostname is
+    # stored to 'name'
+    #
+    def hash_from(request)
+        super.merge('facts' => request.instance.values)
+    end
+
+    # Facts are stored to the 'node' document.
+    def document_type_for(request)
+        'node'
+    end
+
+    # The id used to store the object in couchdb.
+    def id_for(request)
+        request.key.to_s
+    end
+
+end
+
diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb
index 2b086af..0b9fc58 100755
--- a/lib/puppet/node/facts.rb
+++ b/lib/puppet/node/facts.rb
@@ -49,6 +49,11 @@ class Puppet::Node::Facts
         end
     end
 
+    def ==(other)
+        return false unless self.name == other.name
+        strip_internal == other.send(:strip_internal)
+    end
+
     private
 
     # Add internal data to the facts for storage.
diff --git a/spec/fixtures/yaml/test.local.yaml b/spec/fixtures/yaml/test.local.yaml
new file mode 100644
index 0000000..194d8aa
--- /dev/null
+++ b/spec/fixtures/yaml/test.local.yaml
@@ -0,0 +1,16 @@
+--- !ruby/object:Puppet::Node::Facts
+  expiration: 2010-06-07 19:15:36.519351 -07:00
+  name: test.local
+  values: 
+    sp_number_processors: "2"
+    kernelmajversion: "10.3"
+    kernelversion: 10.3.1
+    sp_secure_vm: secure_vm_enabled
+    ps: ps auxwww
+    macosx_productversion_major: "10.6"
+    hostname: test
+    !ruby/sym _timestamp: Mon Jun 07 18:45:36 -0700 2010
+    facterversion: 1.5.7
+    sp_packages: "1"
+    timezone: PDT
+    environment: production
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d657f83..0ea24bb 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -23,6 +23,7 @@ require 'spec/autorun'
 
 # So everyone else doesn't have to include this base constant.
 module PuppetSpec
+    FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
 end
 
 # load any monkey-patches
diff --git a/spec/unit/application/master.rb b/spec/unit/application/master.rb
index f082ece..c3f4d9e 100644
--- a/spec/unit/application/master.rb
+++ b/spec/unit/application/master.rb
@@ -176,12 +176,6 @@ describe Puppet::Application::Master do
             @master.setup
         end
 
-        it "should set node facst terminus to yaml" do
-            Puppet::Node::Facts.expects(:terminus_class=).with(:yaml)
-
-            @master.setup
-        end
-
         it "should cache class in yaml" do
             Puppet::Node.expects(:cache_class=).with(:yaml)
 
diff --git a/spec/unit/indirector/facts/couch.rb b/spec/unit/indirector/facts/couch.rb
new file mode 100644
index 0000000..acc28b9
--- /dev/null
+++ b/spec/unit/indirector/facts/couch.rb
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/node/facts'
+require 'puppet/indirector/facts/couch'
+
+describe Puppet::Node::Facts::Couch do
+    before do
+        @mock_db = mock('couch db')
+        mock_document = CouchRest::Document.new(:_id => fake_request.key, :facts => fake_request.values)
+        mock_document.stubs(:database).returns(@mock_db)
+        @mock_db.stubs(:get).with('test.local').returns(mock_document)
+        Puppet::Node::Facts::Couch.stubs(:db).returns(@mock_db)
+    end
+
+    subject { Puppet::Node::Facts::Couch }
+
+    describe "#find" do
+        it "should find the request by key" do
+            @mock_db.expects(:get).with(fake_request.key).returns({'_id' => fake_request.key, 'facts' => fake_request.instance.values})
+            subject.new.find(fake_request).should == fake_request.instance
+        end
+    end
+
+    describe "#save" do
+        it "should save the json to the CouchDB database" do
+            @mock_db.expects(:save_doc).at_least_once.returns({'ok' => true })
+            subject.new.save(fake_request)
+        end
+    end
+
+    def fake_request
+        facts = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml', 'test.local.yaml'))
+        Struct.new(:instance, :key, :options).new(facts, facts.name, {})
+    end
+    private :fake_request
+
+end
+

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list