summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRein Henrichs <rein@puppetlabs.com>2010-06-14 16:40:38 -0700
committertest branch <puppet-dev@googlegroups.com>2010-02-17 06:50:53 -0800
commit432db2593f15de200767ec16c14f433f718a44d9 (patch)
tree934cdcbacb66a702929e270849675a24c59a140d /lib
parent35636e9984f1f9b2c6fae3d1410b4b08b6311693 (diff)
downloadpuppet-432db2593f15de200767ec16c14f433f718a44d9.tar.gz
puppet-432db2593f15de200767ec16c14f433f718a44d9.tar.xz
puppet-432db2593f15de200767ec16c14f433f718a44d9.zip
[#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
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/defaults.rb4
-rw-r--r--lib/puppet/feature/base.rb3
-rw-r--r--lib/puppet/indirector/couch.rb68
-rw-r--r--lib/puppet/indirector/facts/couch.rb31
-rwxr-xr-xlib/puppet/node/facts.rb5
5 files changed, 111 insertions, 0 deletions
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 78f4cd52e..9de73f526 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 8a21fd30f..0ca408ce4 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 000000000..b328f5cb7
--- /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 000000000..522fe3350
--- /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 2b086afea..0b9fc5879 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.