Skip to content

Commit

Permalink
Fixes #27 - allow loading of external fact hashes
Browse files Browse the repository at this point in the history
  * previously there was no way to supply facterdb with
    external facts that contain sensitive information.  This
    fixes that by allowing the user to set an environment variable
    that take precedence over the facts from this gem.
  • Loading branch information
logicminds committed Oct 14, 2017
1 parent 369c1ec commit 22d0c11
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ if facterversion = ENV['FACTER_GEM_VERSION']
else
gem 'facter', :require => false
end

group :dev do
gem 'pry'
end
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ require 'facterdb'
FacterDB::get_facts('osfamily=Debian')
```

# Facter versions supported
## Facter versions supported

* 1.6
* 1.7
Expand All @@ -72,7 +72,7 @@ FacterDB::get_facts('osfamily=Debian')
* 3.7
* 3.8

# Operating Systems supported
## Operating Systems supported

* AIX
* ArchLinux
Expand Down Expand Up @@ -118,7 +118,7 @@ FacterDB::get_facts('osfamily=Debian')
* Windows 2012 r2
* Windows 7

# Add new Operating System support
## Add new Operating System support

There is `Vagrantfile` to automagically populate `facts` directory by spawning a new VM and launches a provisioning scripts.

Expand All @@ -139,3 +139,36 @@ for file in facts/*/centos-*.facts; do cat $file | sed -e 's/CentOS/RedHat/' > $
for file in facts/*/centos-*.facts; do cat $file | sed -e 's/CentOS/Scientific/' > $(echo $file | sed 's/centos/scientific/'); done
for file in facts/*/centos-*.facts; do cat $file | sed -e 's/CentOS/OracleLinux/' > $(echo $file | sed 's/centos/oraclelinux/'); done
```

## Suppling custom external facts
The default facts are great for many things but there will be times when you need to have facterdb search custom
fact sets that only make sense in your environment or might contain sensitive information.

This can be useful when combined with [rspec_puppet_facts](https://github.com/mcanevet/rspec-puppet-facts) or the [puppet-debugger](https://github.com/nwops/puppet-debugger) which both use this gem.

To supply external facts to facterdb just set the `FACTERDB_SEARCH_PATH` environment variable with one or more comma seperated
paths to your facts. Do this any time facterdb is used directly or indirectly.

Each fact set you create must meet the following requirements:
1. A JSON serialized file containing a single Hash of all the facts.
2. The facts file must end in `.facts`
3. Must be placed inside some directory. You can organize this directory however you like.

Facterdb is smart enough the search your supplied directories for files ending with '.facts'. You can even supply
multiple directories.

Example:

`FACTERDB_SEARCH_PATH="/var/opt/lib/custom_facts"`

or

`FACTERDB_SEARCH_PATH="/var/opt/lib/custom_facts,/tmp/custom_facts, /home/user1/custom_facts"`

We still highly encourage you to create pull requests with new fact sets over using external facts.

You can create these files via many methods.

* `puppet facts | jq '.values' > /tmp/custom_facts/datacenter_a/2.4/os_x.facts` # must have jq command
* Via puppetdb queries
* hand crafted
30 changes: 29 additions & 1 deletion lib/facterdb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,35 @@
module FacterDB

def self.database
@database ||= "[#{Dir.glob("#{File.expand_path(File.join(File.dirname(__FILE__), '../facts'))}/*/*.facts").map { |f| File.read(f) }.join(',')}]\n"
@database ||= "[#{facterdb_fact_files.map { |f| File.read(f) }.join(',')}]\n"
end

# @return [Array[String]] - list of all files found in the default facterdb facts path
def self.default_fact_files
proj_root = File.join(File.dirname(File.dirname(__FILE__)))
facts_dir = File.expand_path(File.join(proj_root, 'facts'))
Dir.glob(File.join(facts_dir, "**", '*.facts'))
end

# @return [Array[String]] - list of all files found in the user supplied facterdb facts path
# @param fact_paths [String] - a comma separated list of paths to search for fact files
def self.external_fact_files(fact_paths = ENV['FACTERDB_SEARCH_PATH'])
fact_paths ||= ''
return [] if fact_paths.empty?
paths = fact_paths.split(',').map do |fact_path|
unless File.directory?(fact_path)
warn("[FACTERDB] Ignoring external facts path #{fact_path} as it is not a directory")
next nil
end
File.join(fact_path.strip, '**', '*.facts')
end.compact
Dir.glob(paths)
end

# @return [Array[String]] - list of all files found in the default facterdb facts path and user supplied path
# @note external fact files supplied by the user will take precedence over default fact files found in this gem
def self.facterdb_fact_files
(external_fact_files + default_fact_files).uniq
end

def self.get_os_facts(facter_version='*', filter=[])
Expand Down
48 changes: 48 additions & 0 deletions spec/facterdb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,54 @@

describe 'FacterDB' do

describe 'database' do

it '#external_fact_files with env variable' do
ENV['FACTERDB_SEARCH_PATH'] = File.join(project_dir, 'facts', '2.4')
expect(FacterDB.external_fact_files.count).to be >= 50
end

it '#external_fact_files with env variable and multiple paths' do
ENV['FACTERDB_SEARCH_PATH'] = [File.join(project_dir, 'facts', '2.4'), File.join(project_dir, 'facts', '2.3')].join(',')
expect(FacterDB.external_fact_files.count).to be >= 150
end

it '#external_fact_files with argument' do
ENV['FACTERDB_SEARCH_PATH'] = nil
path = File.join(project_dir, 'facts', '2.4')
expect(FacterDB.external_fact_files(path).count).to be >= 102
end

it '#external_fact_files without argument or env variable' do
ENV['FACTERDB_SEARCH_PATH'] = nil
expect(FacterDB.external_fact_files.count).to be 0
end

it '#default_fact_files' do
expect(FacterDB.default_fact_files.count).to be >= 1000
end

it '#facterdb_fact_files' do
ENV['FACTERDB_SEARCH_PATH'] = File.join(project_dir, 'facts', '2.4')
external_count = FacterDB.external_fact_files.count
internal_count = FacterDB.default_fact_files.count
# because we call unique on the array we remove the duplicates which skews this test
expect(FacterDB.facterdb_fact_files.count).to eq(internal_count)
end

it '#database' do
ENV['FACTERDB_SEARCH_PATH'] = nil
# to be an incomprehensible string
expect(FacterDB.database).to be_a String
end

it '#database with external paths' do
ENV['FACTERDB_SEARCH_PATH'] = File.join(project_dir, 'facts', '2.4')
# to be an incomprehensible string
expect(FacterDB.database).to be_a String
end
end

describe '#get_os_facts' do
context 'without parameters' do
subject { FacterDB.get_os_facts() }
Expand Down
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
require 'rspec'
require 'facterdb'
include FacterDB

def project_dir
File.dirname File.dirname(File.expand_path(__FILE__))
end

0 comments on commit 22d0c11

Please sign in to comment.