summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/defaults.rb1
-rw-r--r--lib/puppet/indirector/catalog/compiler.rb1
-rw-r--r--lib/puppet/indirector/indirection.rb1
-rw-r--r--lib/puppet/indirector/inventory/yaml.rb81
-rw-r--r--lib/puppet/network/http/api/v1.rb5
-rw-r--r--lib/puppet/network/http/handler.rb46
-rw-r--r--lib/puppet/network/rest_authconfig.rb22
-rw-r--r--lib/puppet/network/rest_authorization.rb4
-rw-r--r--lib/puppet/node.rb1
-rwxr-xr-xlib/puppet/node/facts.rb37
-rw-r--r--lib/puppet/node/inventory.rb7
11 files changed, 163 insertions, 43 deletions
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index ab127602b..c7bebf8f5 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -116,6 +116,7 @@ module Puppet
:catalog_terminus => ["compiler", "Where to get node catalogs. This is useful to change if, for instance,
you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store."],
:facts_terminus => [Puppet.application_name.to_s == "master" ? 'yaml' : 'facter', "The node facts terminus."],
+ :inventory_terminus => [ "$facts_terminus", "Should usually be the same as the facts terminus" ],
:httplog => { :default => "$logdir/http.log",
:owner => "root",
:mode => 0640,
diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb
index c50022fff..1e1ae12b1 100644
--- a/lib/puppet/indirector/catalog/compiler.rb
+++ b/lib/puppet/indirector/catalog/compiler.rb
@@ -22,6 +22,7 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code
else
facts = Puppet::Node::Facts.convert_from(format, text_facts)
end
+ facts.add_timestamp
facts.save
end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 309eed7b6..9095e48f8 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -238,6 +238,7 @@ class Puppet::Indirector::Indirection
if result = terminus.search(request)
raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array)
result.each do |instance|
+ next unless instance.respond_to? :expiration
instance.expiration ||= self.expiration
end
return result
diff --git a/lib/puppet/indirector/inventory/yaml.rb b/lib/puppet/indirector/inventory/yaml.rb
new file mode 100644
index 000000000..fe3489a95
--- /dev/null
+++ b/lib/puppet/indirector/inventory/yaml.rb
@@ -0,0 +1,81 @@
+require 'puppet/node/inventory'
+require 'puppet/indirector/yaml'
+
+class Puppet::Node::Inventory::Yaml < Puppet::Indirector::Yaml
+ desc "Return node names matching the fact query"
+
+ # Return the path to a given node's file.
+ def yaml_dir_path
+ base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir]
+ File.join(base, 'facts', '*.yaml')
+ end
+
+ def node_matches?(facts, options)
+ options.each do |key, value|
+ type, name, operator = key.to_s.split(".")
+ operator ||= 'eq'
+
+ return false unless node_matches_option?(type, name, operator, value, facts)
+ end
+ return true
+ end
+
+ def search(request)
+ node_names = []
+ Dir.glob(yaml_dir_path).each do |file|
+ facts = YAML.load_file(file)
+ node_names << facts.name if node_matches?(facts, request.options)
+ end
+ node_names
+ end
+
+ private
+
+ def node_matches_option?(type, name, operator, value, facts)
+ case type
+ when "meta"
+ case name
+ when "timestamp"
+ compare_timestamp(operator, facts.timestamp, Time.parse(value))
+ end
+ when "facts"
+ compare_facts(operator, facts.values[name], value)
+ end
+ end
+
+ def compare_facts(operator, value1, value2)
+ return false unless value1
+
+ case operator
+ when "eq"
+ value1.to_s == value2.to_s
+ when "le"
+ value1.to_f <= value2.to_f
+ when "ge"
+ value1.to_f >= value2.to_f
+ when "lt"
+ value1.to_f < value2.to_f
+ when "gt"
+ value1.to_f > value2.to_f
+ when "ne"
+ value1.to_s != value2.to_s
+ end
+ end
+
+ def compare_timestamp(operator, value1, value2)
+ case operator
+ when "eq"
+ value1 == value2
+ when "le"
+ value1 <= value2
+ when "ge"
+ value1 >= value2
+ when "lt"
+ value1 < value2
+ when "gt"
+ value1 > value2
+ when "ne"
+ value1 != value2
+ end
+ end
+end
diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb
index dd4612a14..abbb2dfa9 100644
--- a/lib/puppet/network/http/api/v1.rb
+++ b/lib/puppet/network/http/api/v1.rb
@@ -30,7 +30,7 @@ module Puppet::Network::HTTP::API::V1
key = URI.unescape(key)
- Puppet::Indirector::Request.new(indirection, method, key, params)
+ [indirection, method, key, params]
end
def indirection2uri(request)
@@ -57,9 +57,8 @@ module Puppet::Network::HTTP::API::V1
# fix to not need this, and our goal is to move away from the complication
# that leads to the fix being too long.
return :singular if indirection == "facts"
-
- # "status" really is singular
return :singular if indirection == "status"
+ return :plural if indirection == "inventory"
result = (indirection =~ /s$/) ? :plural : :singular
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 61ae2d2fc..82238aa0a 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -61,11 +61,11 @@ module Puppet::Network::HTTP::Handler
# handle an HTTP request
def process(request, response)
- indirection_request = uri2indirection(http_method(request), path(request), params(request))
+ indirection, method, key, params = uri2indirection(http_method(request), path(request), params(request))
- check_authorization(indirection_request)
+ check_authorization(indirection, method, key, params)
- send("do_#{indirection_request.method}", indirection_request, request, response)
+ send("do_#{method}", indirection, key, params, request, response)
rescue SystemExit,NoMemoryError
raise
rescue Exception => e
@@ -96,11 +96,16 @@ module Puppet::Network::HTTP::Handler
set_response(response, exception.to_s, status)
end
+ def model(indirection_name)
+ raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym)
+ indirection.model
+ end
+
# Execute our find.
- def do_find(indirection_request, request, response)
- unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash)
- Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'")
- return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404)
+ def do_find(indirection_name, key, params, request, response)
+ unless result = model(indirection_name).find(key, params)
+ Puppet.info("Could not find #{indirection_name} for '#{key}'")
+ return do_exception(response, "Could not find #{indirection_name} #{key}", 404)
end
# The encoding of the result must include the format to use,
@@ -113,34 +118,35 @@ module Puppet::Network::HTTP::Handler
end
# Execute our search.
- def do_search(indirection_request, request, response)
- result = indirection_request.model.search(indirection_request.key, indirection_request.to_hash)
+ def do_search(indirection_name, key, params, request, response)
+ model = self.model(indirection_name)
+ result = model.search(key, params)
- if result.nil? or (result.is_a?(Array) and result.empty?)
- return do_exception(response, "Could not find instances in #{indirection_request.indirection_name} with '#{indirection_request.key}'", 404)
+ if result.nil?
+ return do_exception(response, "Could not find instances in #{indirection_name} with '#{key}'", 404)
end
format = format_to_use(request)
set_content_type(response, format)
- set_response(response, indirection_request.model.render_multiple(format, result))
+ set_response(response, model.render_multiple(format, result))
end
# Execute our destroy.
- def do_destroy(indirection_request, request, response)
- result = indirection_request.model.destroy(indirection_request.key, indirection_request.to_hash)
+ def do_destroy(indirection_name, key, params, request, response)
+ result = model(indirection_name).destroy(key, params)
return_yaml_response(response, result)
end
# Execute our save.
- def do_save(indirection_request, request, response)
+ def do_save(indirection_name, key, params, request, response)
data = body(request).to_s
raise ArgumentError, "No data to save" if !data or data.empty?
format = request_format(request)
- obj = indirection_request.model.convert_from(format, data)
- result = save_object(indirection_request, obj)
+ obj = model(indirection_name).convert_from(format, data)
+ result = obj.save(key)
return_yaml_response(response, result)
end
@@ -162,12 +168,6 @@ module Puppet::Network::HTTP::Handler
set_response(response, body.to_yaml)
end
- # LAK:NOTE This has to be here for testing; it's a stub-point so
- # we keep infinite recursion from happening.
- def save_object(ind_request, object)
- object.save(ind_request.key)
- end
-
def get?(request)
http_method(request) == 'GET'
end
diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb
index 82d5a9de2..b6a163316 100644
--- a/lib/puppet/network/rest_authconfig.rb
+++ b/lib/puppet/network/rest_authconfig.rb
@@ -32,21 +32,21 @@ module Puppet
# check wether this request is allowed in our ACL
# raise an Puppet::Network::AuthorizedError if the request
# is denied.
- def allowed?(request)
+ def allowed?(indirection, method, key, params)
read
# we're splitting the request in part because
# fail_on_deny could as well be called in the XMLRPC context
# with a ClientRequest.
- @rights.fail_on_deny(
- build_uri(request),
-
- :node => request.node,
- :ip => request.ip,
- :method => request.method,
- :environment => request.environment,
- :authenticated => request.authenticated)
+ @rights.fail_on_deny(
+ build_uri(indirection, key),
+ :node => params[:node],
+ :ip => params[:ip],
+ :method => method,
+ :environment => params[:environment],
+ :authenticated => params[:authenticated]
+ )
end
def initialize(file = nil, parsenow = true)
@@ -90,8 +90,8 @@ module Puppet
@rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil?
end
- def build_uri(request)
- "/#{request.indirection_name}/#{request.key}"
+ def build_uri(indirection_name, key)
+ "/#{indirection_name}/#{key}"
end
end
end
diff --git a/lib/puppet/network/rest_authorization.rb b/lib/puppet/network/rest_authorization.rb
index e052245eb..50f094e3e 100644
--- a/lib/puppet/network/rest_authorization.rb
+++ b/lib/puppet/network/rest_authorization.rb
@@ -15,8 +15,8 @@ module Puppet::Network
end
# Verify that our client has access.
- def check_authorization(request)
- authconfig.allowed?(request)
+ def check_authorization(indirection, method, key, params)
+ authconfig.allowed?(indirection, method, key, params)
end
end
end
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index 2453cd1d5..e8d58e6be 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -3,6 +3,7 @@ require 'puppet/indirector'
# A class for managing nodes, including their facts and environment.
class Puppet::Node
require 'puppet/node/facts'
+ require 'puppet/node/inventory'
require 'puppet/node/environment'
# Set up indirection, so that nodes can be looked for in
diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb
index b77ad22d5..d84d54113 100755
--- a/lib/puppet/node/facts.rb
+++ b/lib/puppet/node/facts.rb
@@ -1,12 +1,17 @@
+require 'time'
+
require 'puppet/node'
require 'puppet/indirector'
+require 'puppet/util/pson'
+
# Manage a given node's facts. This either accepts facts and stores them, or
# returns facts for a given node.
class Puppet::Node::Facts
# Set up indirection, so that nodes can be looked for in
# the node sources.
extend Puppet::Indirector
+ extend Puppet::Util::Pson
# We want to expire any cached nodes if the facts are saved.
module NodeExpirer
@@ -30,7 +35,7 @@ class Puppet::Node::Facts
@name = name
@values = values
- add_internal
+ add_timestamp
end
def downcase_if_necessary
@@ -54,13 +59,37 @@ class Puppet::Node::Facts
strip_internal == other.send(:strip_internal)
end
- private
+ def self.from_pson(data)
+ result = new(data['name'], data['values'])
+ result.values[:_timestamp] = Time.parse(data['timestamp'])
+ result.expiration = Time.parse(data['expiration'])
+ result
+ end
+
+ def to_pson(*args)
+ {
+ 'expiration' => expiration,
+ 'name' => name,
+ 'timestamp' => values[:_timestamp],
+ 'values' => values.reject {|k,v| k == :_timestamp},
+ }.to_pson(*args)
+ end
# Add internal data to the facts for storage.
- def add_internal
- self.values[:_timestamp] = Time.now
+ def add_timestamp
+ self.timestamp = Time.now
end
+ def timestamp=(time)
+ self.values[:_timestamp] = time
+ end
+
+ def timestamp
+ self.values[:_timestamp]
+ end
+
+ private
+
# Strip out that internal data.
def strip_internal
newvals = values.dup
diff --git a/lib/puppet/node/inventory.rb b/lib/puppet/node/inventory.rb
new file mode 100644
index 000000000..fd99163b0
--- /dev/null
+++ b/lib/puppet/node/inventory.rb
@@ -0,0 +1,7 @@
+require 'puppet/node'
+require 'puppet/indirector'
+
+class Puppet::Node::Inventory
+ extend Puppet::Indirector
+ indirects :inventory, :terminus_setting => :inventory_terminus
+end