Forge Home

facter_cacheable

Provide a Cache for Facter facts

56,188 downloads

14,898 latest version

4.6 quality score

We run a couple of automated
scans to help you access a
module's quality. Each module is
given a score based on how well
the author has formatted their
code and documentation and
modules are also checked for
malware using VirusTotal.

Please note, the information below
is for guidance only and neither of
these methods should be considered
an endorsement by Puppet.

Version information

  • 1.1.1 (latest)
  • 1.1.0
  • 1.0.2
  • 1.0.1
  • 1.0.0
  • 0.2.2
  • 0.2.1
  • 0.2.0
  • 0.1.2
  • 0.1.0
released Mar 27th 2017
This version is compatible with:
  • , , , , , ,

Start using this module

  • r10k or Code Manager
  • Bolt
  • Manual installation
  • Direct download

Add this module to your Puppetfile:

mod 'waveclaw-facter_cacheable', '0.1.2'
Learn more about managing modules with a Puppetfile

Add this module to your Bolt project:

bolt module add waveclaw-facter_cacheable
Learn more about using this module with an existing project

Manually install this module globally with Puppet module tool:

puppet module install waveclaw-facter_cacheable --version 0.1.2

Direct download is not typically how you would use a Puppet module to manage your infrastructure, but you may want to download the module in order to inspect the code.

Download

Documentation

waveclaw/facter_cacheable — version 0.1.2 Mar 27th 2017

facter_cacheable

| Build Status | Code Climate | Test Coverage |

Table of Contents

  1. Overview
  2. Module Description - What the module does and why it is useful
  3. Setup - The basics of getting started with facter_cacheable
  4. Usage - Configuration options and additional functionality
  5. Reference - An under-the-hood peek at what the module is doing and how
  6. Limitations - OS compatibility, etc.
  7. Development - Guide for contributing to the module

Overview

facter_cacheable implements a Puppet feature for Facter that caches fact values for a given time.

The features are inspired by the Puppet Blog on Facter from 2010.

This does not work correctly with Puppet Enterprise 2016 as it purges the puginsynced facts directory on each run.

Module Description

As mentioned in many getting started with Puppet guides, including some by Puppet Labs, caching a fact can be useful. A well-maintained cache can:

  • reduce frequency of expensive calls
  • store values reachable outside of Puppet agent runs
  • explicitly control schedule of fact refreshing

There is limited planned support in Facter 2.0 and later for controlling some caching of Puppet facts. Personally this developer has never seen it in the wild.

No, this is not yet-another-varnish module either.

Setup

What facter_cacheable affects

Deploys a feature, facter_cacheable, which is accessed by a custom fact written by a developer.

Setup Requirements

PluginSync must be enabled on at least one Puppet agent run to deploy the module.

Beginning with facter_cacheable

Usage

This module accepts no customization. The facter_cache call takes options for only the value to cache, the time-to-live(ttl) and an optional format to store the cache in.

If the directories containing the cache files do not exist, the module will not create them. That is left to the discretion of the end user.

To cache a value use cache:

require 'facter/util/facter_cacheable'
Facter::Util::Facter_cacheable.cache(
  :fact_name_symbol,
  some_value,
  optional_cache_file
  )

To return a cached value use cached?:

require 'facter/util/facter_cacheable'
Facter::Util::Facter_cacheable.cached?(
  :fact_name_symbol,
  ttl_in_seconds,
  optional_cache_file)

Complete Example

#
# my_module/lib/facter/my_custom_fact.rb
#
require 'facter'
require 'puppet/util/facter_cachable'

Facter.add(:my_custom_fact) do
  confine do
    Puppet.features.facter_cacheable?
  end
  setcode do
    # 24 * 3600 = 1 day of seconds
    cache = Facter::Util::Facter_cacheable.cached?(:my_custom_fact, 24 * 3600)
    if ! cache
      my_value = some_expensive_operation()
      # store the value for later
      Facter::Util::Facter_cacheable.cache(:my_custom_fact, my_value)
      # return the expensive value
      my_value
    else
      # return the cached value (this may need processing)
      cache
    end
  end
end

It is not required but encouraged to keep the name of the cache and fact consistent. Although with all Ruby programming, sanity is optional. Just like the documentation.

YAML stored values may appear as arrays or string-indexed hashes depending on the version of Puppet and Facter involved. Unpacking those is left as an exercise for the reader.

Testing Code

To test code that uses Facter_cacheable you will have to resort to a little used method for stubbing objects.

In your Facter fact, guard against import of the module which will fail if you do not have it deployed to the Puppet environment on which the tests are running.

Note: even the rSpec setup will not properly install this utility for testing.

begin
    require 'facter/util/facter_cacheable'
  rescue LoadError => e
    Facter.debug("#{e.backtrace[0]}: #{$!}.")
end
# regular fact like the complete example above

In the rSpec Facter tests, normally some kind of function test on Facter.value(), setup a harness which can check for invocation of the cache functions.

context 'test caching' do
  let(:fake_class) { Class.new }
  before :each do
    allow(File).to receive(:exist?).and_call_original
    allow(Puppet.features).to receive(:facter_cacheable?) { true }
    Facter.clear
  end
  it 'should return and save a computed value with an empty cache' do
    stub_const("Facter::Util::Facter_cacheable", fake_class)
    expect(Facter::Util::Facter_cacheable).to receive(:cached?).with(
    :my_fact, 24 * 3600) { nil }
    expect(Facter::Util::Resolution).to receive(:exec).with(
    'some special comand') { mydata }
    expect(Facter::Util::Facter_cacheable).to receive(:cache).with(
      :my_fact, mydata)
    expect(Facter.value(:my_fact).to eq(mydata)
  end
  it 'should return a cached value with a full cache' do
    stub_const("Facter::Util::Facter_cacheable", fake_class)
    expect(Facter::Util::Facter_cacheable).to receive(:cached?).with(
    :my_fact, 24 * 3600) { mydata }
    expect(mod).to_not receive(:my_fact)
    expect(Facter.value(:my_fact)).to eq(mydata)
  end
end

The key parts are the :fake_class and the stub_const() calls. These setup a kind of double that can be used by rSpec to hook into the Facter context.

Reference

Limitations

Supports F/OSS Puppet 3.3.0 - 4.0.0. Tested on AIX, recent vintage Solaris, SuSE, RedHat and RedHat-derivatives.

Does not support Puppet Enterprise due to the cached value wipe on each run.

Don't be surprised if is works elsewhere, too. Or if it sets you house on fire.

The name of this module, facter_cacheable, was chosen to not conflict with other existing implementations such as the Facter::Util::Cacheable support in early implementations of waveclaw/subscription_manager.

Development

Please see CONTRIBUTING for advice on contributions.