commit 49cd56bbee91bb0994d859f98e5a86c9928032a5 Author: Kienan Stewart Date: Sun Nov 14 19:51:23 2021 -0500 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..8fc09c3 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +This module provides a redis terminus for storing configuration from puppet. + +A redis instance can be used for caching facts (via routes.yaml), and/or as a +backend for storeconfigs. When used as such a backend, PuppetDB is no longer +required in order to use exported resources. + +# Pre-requisites + +redis running on localhost, on the default port + +# Installation + +1. Install the ruby files: + + cp -r src/lib/* /usr/lib/ruby/vendor_ruby + +2. Update routes, `/etc/puppet/routes.yaml`: eg., ``` +--- +master: + facts: + terminus: redis + cache: yaml +``` + +3. In the `/etc/puppet/puppet.conf` master section: ``` +[master] + storeconfigs = true + storeconfigs_backend = redis +``` + +4. Restart the puppet server or rack application, eg. ``` +service apache2 restart +``` + +# License + +GPLv3 diff --git a/lib/puppet/indirector/catalog/redis.rb b/lib/puppet/indirector/catalog/redis.rb new file mode 100644 index 0000000..7ab96ef --- /dev/null +++ b/lib/puppet/indirector/catalog/redis.rb @@ -0,0 +1,16 @@ +require 'puppet/resource/catalog' +require 'puppet/indirector/rest' +require 'redis' + +class Puppet::Resource::Catalog::Redis < Puppet::Indirector::REST + + def save(request) + redis = Redis.new + environment = request.options[:environment] || request.environment.to_s + redis.set "catalog_#{request.key}_#{environment}", request.instance.to_json + end + + def find(request) + nil + end +end diff --git a/lib/puppet/indirector/facts/redis.rb b/lib/puppet/indirector/facts/redis.rb new file mode 100644 index 0000000..a7a3278 --- /dev/null +++ b/lib/puppet/indirector/facts/redis.rb @@ -0,0 +1,39 @@ +require 'puppet/node/facts' +require 'puppet/indirector/rest' +require 'json' +require 'redis' + +class Puppet::Node::Facts::Redis < Puppet::Indirector::REST + def get_trusted_info(node) + trusted = Puppet.lookup(:trusted_information) do + Puppet::Context::TrustedInformation.local(node) + end + trusted.to_h + end + + def delete(request) + redis = Redis.new + environment = request.options[:environment] || request.environment.to_s + key = "node_facts_#{request.key}_#{environment}" + redis.del key + end + def find(request) + redis = Redis.new + environment = request.options[:environment] || request.environment.to_s + key = "node_facts_#{request.key}_#{environment}" + values = redis.get key + print values + Puppet::Node::Facts.new(request.key, values) + end + + def save(request) + redis = Redis.new + environment = request.options[:environment] || request.environment.to_s + request.instance.values.merge(get_trusted_info(request.node)) + facts = request.instance.dup + facts.values = facts.values.dup + facts.values[:trusted] = get_trusted_info(request.node) + key = "node_facts_#{facts.name}_#{environment}" + redis.set key, facts.values.to_json + end +end diff --git a/lib/puppet/indirector/resource/redis.rb b/lib/puppet/indirector/resource/redis.rb new file mode 100644 index 0000000..a27fdd6 --- /dev/null +++ b/lib/puppet/indirector/resource/redis.rb @@ -0,0 +1,57 @@ +require 'puppet/indirector/rest' +require 'json' +require 'redis' + +class Puppet::Resource::Redis < Puppet::Indirector::REST + def search(request) + redis = Redis.new + host = request.options[:host] + type = request.key + # I'm not really sure what filter might be + # In the puppetdb terminus it gets append to the default query + # (which is detailed below) + # filter = request.options[:filter] + scope = request.options[:scope] + environment = request.options[:environment] || request.environment.to_s + + # In the puppetdb storeconfigs terminus, the query is + # expr = ['and', + # ['=', 'type', type], + # ['=', 'exported', true], + # ['not', + # '=', 'certname', host]]] + # + # This means that it gets all exported resources of that type + # from all hosts that aren't the request's host. + # Since we sort a catalog entry per host, we need to check all + # keys matching "catalog_*_#{environment}" + # excluding "catalog_#{host}_#{enviroment}". + # This means we will have to make 1 request for the keys, + # and then n-1 requests. + # + key = "catalog_#{host}_#{environment}" + resources = [] + keys = redis.keys("catalog_*_#{environment}") + keys.each do |k| + next if k == key + catalog = JSON.parse(redis.get(k)) + catalog['resources'].each do |res| + # Skip resources that don't match the type + next if res['type'] != type + # Skip non-exported resources + next if not res['exported'] + params = res['parameters'] || {} + params = params.map do |name, value| + Puppet::Parser::Resource::Param.new(:name => name, :value => value) + end + attrs = {:parameters => params, :scope => scope} + t = res['type'] + t = Puppet::Pops::Evaluator::Runtime3ResourceSupport.find_resource_type(scope, t) unless t == 'class' || t == 'node' + result = Puppet::Parser::Resource.new(t, res['title'], attrs) + result.collector_id = "#{res['certname']}|#{res['type']}|#{res['title']}" + resources.append(result) + end + end + resources + end +end