Version information
Start using this module
Add this module to your Puppetfile:
mod 'raphink-policy', '0.7.3'
Learn more about managing modules with a PuppetfileDocumentation
Policy module for Puppet
Your Policy Driven Infrastructure Starter Kit
Requirements
This module requires the following Ruby gems:
rspec
;rspec-puppet
for catalog tests;serverspec
(>= 2.0.0) for functional tests.
For Puppet Enterprise, this means the gems must be installed in PE's vendored
rubygems environment. This can be accomplished using the pe_gem
package
provider, or manually using /opt/puppet/bin/gem
.
Installing
The policy module should be copied to the modulepath
which generates
catalogs for the puppet master. Pluginsync will ensure it is installed at the
master's next puppet run.
Next, routes.yaml must be configured to use the termini of your choice. See the sections below for details of how to configure routes.yaml.
Catalog policies
This module provides a new Puppet terminus which allows to evaluate rspec tests on the actual compiled catalog.
In order to use this terminus:
-
Run Puppet with
pluginsync
on the Puppet master to copy the indirectors; -
Set your
$confdir/routes.yaml
to use the terminus:master: catalog: terminus: compiler_spec
-
Restart your Puppet master process
How it works
The catalog policy compiler, though it replaces the built in compiler, does not compile catalogs on its own. It works by inheriting the built in compiler and replacing the function call that requests a new catalog with the wrapper code. The process essentially looks like this:
When a catalog is requested:
- Call the built in compiler
- Extract all facter data from the compiled catalog
- Pass the catalog to RSpec along with a
facts
hash with all facts - Call every *_spec.rb file in
$manifestdir/../policy
that are in a directory matching a declared class - Fail the catalog if any of the tests fail
The compiler_spec
terminus extends the compiler
terminus for catalogs. After retrieving the catalog using the compiler
terminus, it applies rspec tests to it:
- The rspec tests must be located in
:manifestdir/../policy/catalog/class
, in sub-directories by class; - Only the directories named after classes declared in the catalog will be tested;
rspec-puppet
matchers are already loaded, so they are available in tests;- the catalog is readily available in the tests, along with a
facts
object.
Sample output:
# puppet agent -t
info: Retrieving plugin
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Catalog failed to pass security policies:
-- Failed policy: expected that the catalogue would contain Package[pe-mcollective]
-- Failed policy: expected that the catalogue would not contain Service[pe-mcollective]
notice: Using cached catalog
Writing tests
All files in $manifestdir/../policy
that end with _spec.rb
and are located
in a directory matching a declared class name will be executed by
the policy compiler. Any Ruby, RSpec, or rspec-puppet code is valid in these
files.
Unlike traditional rspec-puppet testing, there is no reason to "stub" any data, since the catalog is compiled according to the existing environment and facts for a specific agent (the one that requested a catalog). Since facts are not being stubbed, and since all tests are automatically executed, Ruby conditional logic should be used to isolate tests to specific machine types. For example:
# security_spec.rb
describe "when a catalog is compiled", :type => :catalog do
if facts['osfamily'] =~ /RedHat/ then
it { should contain_class('selinux').with_mode('enforcing') }
elsif facts['osfamily'] =~ /Windows/ then
it { should contain_exec('shutdown /s /t 01') }
end
end
Server policies
After the catalog has been tested and applied, you might want to run functional tests against the machine. This module provides a rest_spec
terminus for the report indirector which executes rspec tests using the serverspec
matchers.
In order to use it:
- The rspec tests must be located in
:vardir/policy/server
(tests can be deployed using thepolicy::serverspec
define); serverspec
matchers are already loaded, so they are available in tests.
To activate the terminus, you need set it in $confdir/routes.yaml
:
agent:
report:
terminus: rest_spec
This indirector will automatically generate serverspec tests from the catalog for known resource types, making the catalog self-asserting. Currently, it supports the following resource types:
- Package
- Service
- File
- User
Sample output:
# puppet agent -t
info: Retrieving plugin
info: Caching catalog for foo.example.com
info: Applying configuration version 'raphink/a2c8e0f [+]'
... Applying changes ...
notice: Finished catalog run in 59.19 seconds
err: Could not send report: Unit tests failed:
FF
Failures:
1) augeas
Failure/Error: it { should be_installed }
expected "augeas" to be installed
# /var/lib/puppet/policy/server/package_spec.rb:2
# /var/lib/puppet/lib/puppet/indirector/report/rest_spec.rb:45:in `save'
2) /usr/share/augeas/lenses/dist
Failure/Error: it { should be_file }
expected "/usr/share/augeas/lenses/dist" to be file
# /var/lib/puppet/policy/server/package_spec.rb:6
# /var/lib/puppet/lib/puppet/indirector/report/rest_spec.rb:45:in `save'
Finished in 0.06033 seconds
2 examples, 2 failures
Failed examples:
rspec /var/lib/puppet/policy/server/package_spec.rb:2 # augeas
rspec /var/lib/puppet/policy/server/package_spec.rb:6 # /usr/share/augeas/lenses/dist
Writing new automatic serverspec plugins
The rest_spec
report terminus automatically generates serverspec test files from the Puppet catalog, by mapping Puppet resources to Serverspec resources.
New plugins need to be distributed using pluginsync
. They should be placed in the lib/puppetx/policy/auto_spec
directory.
Here is an example:
Puppetx::Policy::AutoSpec.newspec 'Openldap_database' do |o|
should = (o[:ensure] == 'absent') ? 'should_not' : 'should'
content = " describe command('ldapsearch -LLL -x -b #{o[:suffix]}') do\n"
content += " its(:stdout) { #{should} match /dn: #{o[:suffix]}/ }\n"
content += " end\n"
end
It also works with defined resource types:
Puppetx::Policy::AutoSpec.newspec 'Apache::Vhost' do |v|
should = (p[:ensure] == 'absent') ? 'should_not' : 'should'
" describe port('#{v[:port]}') do\n it { #{should} be_listening }\n end\n" if v[:port]
end
Using the MCollective agent
This module provides an MCollective agent in files/mcollective/agent
. This agent currently has two actions:
Documentation
$ mco plugin doc spec
RSpec tests
===========
RSpec tests
Author: Raphaël Pinson
Version: 0.1
License: GPLv3
Timeout: 60
Home Page:
ACTIONS:
========
check, run
check action:
-------------
Run a check with the serverspec library
INPUT:
action:
Description:
Prompt: Action to check
Type: string
Validation: ^\S+$
Length: 50
values:
Description:
Prompt: Values to check
Type: string
Validation: ^\S+$
Length: 100
OUTPUT:
passed:
Description: Whether the checked passed
Display As: Passed
run action:
-----------
Run Puppet-policy server tests
INPUT:
OUTPUT:
output:
Description: Output of tests
Display As: Output
passed:
Description: Whether the tests passed
Display As: Passed
Examples
Using the check
action:
$ mco rpc spec check action=running values=ssh
Discovering hosts using the mc method for 2 second(s) .... 1
* [ ============================================================> ] 1 / 1
wrk4
Passed: true
Finished processing 1 / 1 hosts in 373.44 ms
Using the run
action:
$ mco rpc spec run
Discovering hosts using the mc method for 2 second(s) .... 1
* [ ============================================================> ] 1 / 1
wrk4
Output: F
Failures:
1) abc
Failure/Error: it { should be_running }
expected "abc" to be running
# /var/lib/puppet/policy/server/my_test_spec.rb:3
# /usr/share/mcollective/plugins/mcollective/agent/spec.rb:75:in `run_action'
Finished in 0.00926 seconds
1 example, 1 failure
Failed examples:
rspec /var/lib/puppet/policy/server/my_test_spec.rb:3 # abc
Passed: false
Finished processing 1 / 1 hosts in 316.46 ms
Contributing
Please report bugs and feature request using GitHub issue tracker.
For pull requests, it is very much appreciated to check your Puppet manifest with puppet-lint to follow the recommended Puppet style guidelines from the Puppet Labs style guide.
License
Copyright (c) 2013-2014 Raphaël Pinson
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
0.7.3
Changes
- Fix provider test in package auto_spec
0.7.2
Changes
- Do not use the wrap parameter
0.7.1
Changes
- Make sure spec_dir exists
0.7.0
Changes
- Merged code from puppet-policy_compiler (thanks to Hunger Haugen)
- Remove agent-side catalog terminus
0.6.0
Changes
- Add Group auto_spec plugin
- Add Host auto_spec plugin
- Add basic unit tests and coverage for auto_spec plugins
0.5.3
Changes
- Improve documentation on auto_spec plugins
0.5.2
Changes
- Fix User plugin when user is absent
- Allow several auto_spec plugins for the same resource type
- Add some debug
- Fix spec MCollective agent when calling RSpec.configure
0.5.1
Changes
- Improve doc for auto_spec plugins
0.5.0
Changes
- Make auto_spec pluggable
0.4.2
Changes
- Fix serverspec parameter in policy class
0.4.1
Changes
- Create the two levels of directories required for specs
0.4.0
Changes
- Renamed module as puppet-policy
- Fixed paths in MCollective agent
0.3.0
Changes
- Simplify report terminus by putting everything in :vardir/spec/server
- Add a new "spec" class to setup directories
0.2.1
Changes
- Some metadata fixes
0.2.0
Changes
- Automatically generate serverspec code from Puppet catalog in the report indirector
- Port code to serverspec/specinfra v2