Pull in work from private Subversion repository
This commit is contained in:
commit
ee1fe7a023
6 changed files with 403 additions and 0 deletions
49
README
Normal file
49
README
Normal file
|
@ -0,0 +1,49 @@
|
|||
A Puppet module that can construct files from fragments.
|
||||
|
||||
Please see the comments in the various .pp files for details
|
||||
as well as posts on my blog at www.devco.net
|
||||
|
||||
Released under the Apache 2.0 licence
|
||||
|
||||
KNOWN ISSUES:
|
||||
- In 0.24.8 you will see inintended notifies, if you build a file
|
||||
in a run, the next run will also see it as changed. This is due
|
||||
to how 0.24.8 does the purging of unhandled files, this is improved
|
||||
in 0.25.x and we cannot work around it in our code.
|
||||
|
||||
- At present you cannot change the ownership of the file by just setting
|
||||
the property on the resources, we have a work around in mind.
|
||||
|
||||
CHANGELOG:
|
||||
- 2010/02/19 - initial release
|
||||
- 2010/03/12 - add support for 0.24.8 and newer
|
||||
- make the location of sort configurable
|
||||
- add the ability to add shell comment based warnings to
|
||||
top of files
|
||||
- add the ablity to create empty files
|
||||
- 2010/04/05 - fix parsing of WARN and change code style to match rest
|
||||
of the code
|
||||
- Better and safer boolean handling for warn and force
|
||||
- Don't use hard coded paths in the shell script, set PATH
|
||||
top of the script
|
||||
- Use file{} to copy the result and make all fragments owned
|
||||
by root. This means we can chnage the ownership/group of the
|
||||
resulting file at any time.
|
||||
- You can specify ensure => "/some/other/file" in concat::fragment
|
||||
to include the contents of a symlink into the final file.
|
||||
- 2010/04/16 - Add more cleaning of the fragment name - removing / from the $name
|
||||
|
||||
CONTRIBUTORS:
|
||||
Paul Elliot - Provided 0.24.8 support, shell warnings and empty file
|
||||
creation support.
|
||||
Chad Netzer - Various patches to improve safety of file operations
|
||||
- Symlink support
|
||||
David Schmitt - Patch to remove hard coded paths relying on OS path
|
||||
- Patch to use file{} to copy the resulting file to the
|
||||
final destination. This means Puppet client will show
|
||||
diffs and that hopefully we can change file ownerships
|
||||
now
|
||||
|
||||
|
||||
CONTACT:
|
||||
R.I.Pienaar - rip@devco.net / www.devco.net / @ripienaar
|
123
files/concatfragments.sh
Executable file
123
files/concatfragments.sh
Executable file
|
@ -0,0 +1,123 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Script to concat files to a config file.
|
||||
#
|
||||
# Given a directory like this:
|
||||
# /path/to/conf.d
|
||||
# |-- fragments
|
||||
# | |-- 00_named.conf
|
||||
# | |-- 10_domain.net
|
||||
# | `-- zz_footer
|
||||
#
|
||||
# The script supports a test option that will build the concat file to a temp location and
|
||||
# use /usr/bin/cmp to verify if it should be run or not. This would result in the concat happening
|
||||
# twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds.
|
||||
#
|
||||
# Without the test option and the unless combo your services that depend on the final file would end up
|
||||
# restarting on each run, or in other manifest models some changes might get missed.
|
||||
#
|
||||
# OPTIONS:
|
||||
# -o The file to create from the sources
|
||||
# -d The directory where the fragments are kept
|
||||
# -t Test to find out if a build is needed, basically concats the files to a temp
|
||||
# location and compare with what's in the final location, return codes are designed
|
||||
# for use with unless on an exec resource
|
||||
# -w Add a shell style comment at the top of the created file to warn users that it
|
||||
# is generated by puppet
|
||||
# -f Enables the creation of empty output files when no fragments are found
|
||||
# -n Sort the output numerically rather than the default alpha sort
|
||||
#
|
||||
# the command:
|
||||
#
|
||||
# concatfragments.sh -o /path/to/conffile.cfg -d /path/to/conf.d
|
||||
#
|
||||
# creates /path/to/conf.d/fragments.concat and copies the resulting
|
||||
# file to /path/to/conffile.cfg. The files will be sorted alphabetically
|
||||
# pass the -n switch to sort numerically.
|
||||
#
|
||||
# The script does error checking on the various dirs and files to make
|
||||
# sure things don't fail.
|
||||
|
||||
OUTFILE=""
|
||||
WORKDIR=""
|
||||
TEST=""
|
||||
FORCE=""
|
||||
WARN=""
|
||||
SORTARG="-z"
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
|
||||
while getopts "o:s:d:tnwf" options; do
|
||||
case $options in
|
||||
o ) OUTFILE=$OPTARG;;
|
||||
d ) WORKDIR=$OPTARG;;
|
||||
n ) SORTARG="-zn";;
|
||||
w ) WARN="true";;
|
||||
f ) FORCE="true";;
|
||||
t ) TEST="true";;
|
||||
* ) echo "Specify output file with -o and fragments directory with -d"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
# do we have -o?
|
||||
if [ x${OUTFILE} = "x" ]; then
|
||||
echo "Please specify an output file with -o"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# do we have -d?
|
||||
if [ x${WORKDIR} = "x" ]; then
|
||||
echo "Please fragments directory with -d"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# can we write to -o?
|
||||
if [ -a ${OUTFILE} ]; then
|
||||
if [ ! -w ${OUTFILE} ]; then
|
||||
echo "Cannot write to ${OUTFILE}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [ ! -w `dirname ${OUTFILE}` ]; then
|
||||
echo "Cannot write to `dirname ${OUTFILE}` to create ${OUTFILE}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# do we have a fragments subdir inside the work dir?
|
||||
if [ ! -d "${WORKDIR}/fragments" ] && [ ! -x "${WORKDIR}/fragments" ]; then
|
||||
echo "Cannot access the fragments directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# are there actually any fragments?
|
||||
if [ ! "$(ls -A ${WORKDIR}/fragments)" ]; then
|
||||
if [ x${FORCE} = "x" ]; then
|
||||
echo "The fragments directory is empty, cowardly refusing to make empty config files"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ${WORKDIR}
|
||||
|
||||
if [ x${WARN} = "x" ]; then
|
||||
cat /dev/null > "fragments.concat"
|
||||
else
|
||||
echo '# This file is managed by Puppet. DO NOT EDIT.' > "fragments.concat"
|
||||
fi
|
||||
|
||||
# find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir
|
||||
find fragments/ -type f -follow -print0 |sort ${SORTARG}|xargs -0 cat >>"fragments.concat"
|
||||
|
||||
if [ x${TEST} = "x" ]; then
|
||||
# This is a real run, copy the file to outfile
|
||||
cp fragments.concat ${OUTFILE}
|
||||
RETVAL=$?
|
||||
else
|
||||
# Just compare the result to outfile to help the exec decide
|
||||
cmp ${OUTFILE} fragments.concat
|
||||
RETVAL=$?
|
||||
fi
|
||||
|
||||
exit $RETVAL
|
0
files/null/.gitignore
vendored
Normal file
0
files/null/.gitignore
vendored
Normal file
48
manifests/fragment.pp
Executable file
48
manifests/fragment.pp
Executable file
|
@ -0,0 +1,48 @@
|
|||
# Puts a file fragment into a directory previous setup using concat
|
||||
#
|
||||
# OPTIONS:
|
||||
# - target The file that these fragments belong to
|
||||
# - content If present puts the content into the file
|
||||
# - source If content was not specified, use the source
|
||||
# - order By default all files gets a 10_ prefix in the directory
|
||||
# you can set it to anything else using this to influence the
|
||||
# order of the content in the file
|
||||
# - ensure Present/Absent
|
||||
# - mode Mode for the file
|
||||
# - owner Owner of the file
|
||||
# - group Owner of the file
|
||||
define concat::fragment($target, $content='', $source='', $order=10, $ensure = "present", $mode = 0644, $owner = root, $group = root) {
|
||||
$safe_name = regsubst($name, '/', '_', 'G')
|
||||
$safe_target_name = regsubst($target, '/', '_', 'G')
|
||||
$concatdir = $concat::setup::concatdir
|
||||
$fragdir = "${concatdir}/${safe_target_name}"
|
||||
|
||||
# if content is passed, use that, else if source is passed use that
|
||||
# if neither passed, but $ensure is in symlink form, make a symlink
|
||||
case $content {
|
||||
"": {
|
||||
case $source {
|
||||
"": {
|
||||
case $ensure {
|
||||
"", "absent", "present", "file", "directory": {
|
||||
crit("No content or source specified")
|
||||
}
|
||||
}
|
||||
}
|
||||
default: { File{ source => $source } }
|
||||
}
|
||||
}
|
||||
default: { File{ content => $content } }
|
||||
}
|
||||
|
||||
file{"${fragdir}/fragments/${order}_${safe_name}":
|
||||
mode => $mode,
|
||||
owner => $owner,
|
||||
group => $group,
|
||||
ensure => $ensure,
|
||||
alias => "concat_fragment_${name}",
|
||||
notify => Exec["concat_${target}"]
|
||||
}
|
||||
}
|
||||
|
||||
# vi:tabstop=4:expandtab:ai
|
147
manifests/init.pp
Executable file
147
manifests/init.pp
Executable file
|
@ -0,0 +1,147 @@
|
|||
# A system to construct files using fragments from other files or templates.
|
||||
#
|
||||
# This requires at least puppet 0.25 to work correctly as we use some
|
||||
# enhancements in recursive directory management and regular expressions
|
||||
# to do the work here.
|
||||
#
|
||||
# USAGE:
|
||||
# The basic use case is as below:
|
||||
#
|
||||
# concat{"/etc/named.conf":
|
||||
# notify => Service["named"]
|
||||
# }
|
||||
#
|
||||
# concat::fragment{"foo.com_config":
|
||||
# target => "/etc/named.conf",
|
||||
# order => 10,
|
||||
# content => template("named_conf_zone.erb")
|
||||
# }
|
||||
#
|
||||
# This will use the template named_conf_zone.erb to build a single
|
||||
# bit of config up and put it into the fragments dir. The file
|
||||
# will have an number prefix of 10, you can use the order option
|
||||
# to control that and thus control the order the final file gets built in.
|
||||
#
|
||||
# SETUP:
|
||||
# The class concat::setup defines a variable $concatdir - you should set this
|
||||
# to a directory where you want all the temporary files and fragments to be
|
||||
# stored. Avoid placing this somewhere like /tmp since you should never
|
||||
# delete files here, puppet will manage them.
|
||||
#
|
||||
# If you are on version 0.24.8 or newer you can set $puppetversion to 24 in
|
||||
# concat::setup to enable a compatible mode, else just leave it on 25
|
||||
#
|
||||
# Before you can use any of the concat features you should include the
|
||||
# class concat::setup somewhere on your node first.
|
||||
#
|
||||
# DETAIL:
|
||||
# We use a helper shell script called concatfragments.sh that gets placed
|
||||
# in /usr/local/bin to do the concatenation. While this might seem more
|
||||
# complex than some of the one-liner alternatives you might find on the net
|
||||
# we do a lot of error checking and safety checks in the script to avoid
|
||||
# problems that might be caused by complex escaping errors etc.
|
||||
#
|
||||
# LICENSE:
|
||||
# Apache Version 2
|
||||
#
|
||||
# HISTORY:
|
||||
# 2010/02/19 - First release based on earlier concat_snippets work
|
||||
#
|
||||
# CONTACT:
|
||||
# R.I.Pienaar <rip@devco.net>
|
||||
# Volcane on freenode
|
||||
# @ripienaar on twitter
|
||||
# www.devco.net
|
||||
|
||||
|
||||
# Sets up so that you can use fragments to build a final config file,
|
||||
#
|
||||
# OPTIONS:
|
||||
# - mode The mode of the final file
|
||||
# - owner Who will own the file
|
||||
# - group Who will own the file
|
||||
# - force Enables creating empty files if no fragments are present
|
||||
# - warn Adds a normal shell style comment top of the file indicating
|
||||
# that it is built by puppet
|
||||
#
|
||||
# ACTIONS:
|
||||
# - Creates fragment directories if it didn't exist already
|
||||
# - Executes the concatfragments.sh script to build the final file, this script will create
|
||||
# directory/fragments.concat and copy it to the final destination. Execution happens only when:
|
||||
# * The directory changes
|
||||
# * fragments.concat != final destination, this means rebuilds will happen whenever
|
||||
# someone changes or deletes the final file. Checking is done using /usr/bin/cmp.
|
||||
# * The Exec gets notified by something else - like the concat::fragment define
|
||||
# - Defines a File resource to ensure $mode is set correctly but also to provide another
|
||||
# means of requiring
|
||||
#
|
||||
# ALIASES:
|
||||
# - The exec can notified using Exec["concat_/path/to/file"] or Exec["concat_/path/to/directory"]
|
||||
# - The final file can be referened as File["/path/to/file"] or File["concat_/path/to/file"]
|
||||
define concat($mode = 0644, $owner = "root", $group = "root", $warn = "false", $force = "false") {
|
||||
$safe_name = regsubst($name, '/', '_', 'G')
|
||||
$concatdir = $concat::setup::concatdir
|
||||
$version = $concat::setup::majorversion
|
||||
$fragdir = "${concatdir}/${safe_name}"
|
||||
$concat_name = "fragments.concat.out"
|
||||
|
||||
case $warn {
|
||||
'true',true,yes,on: { $warnflag = "-w" }
|
||||
'false',false,no,off: { $warnflag = "" }
|
||||
default: { fail("Improper 'warn' value given to concat: $warn") }
|
||||
}
|
||||
|
||||
case $force {
|
||||
'true',true,yes,on: { $forceflag = "-f" }
|
||||
'false',false,no,off: { $forceflag = "" }
|
||||
default: { fail("Improper 'force' value given to concat: $force") }
|
||||
}
|
||||
|
||||
File{
|
||||
owner => root,
|
||||
group => root,
|
||||
mode => $mode,
|
||||
}
|
||||
|
||||
file{$fragdir:
|
||||
ensure => directory;
|
||||
|
||||
"${fragdir}/fragments":
|
||||
ensure => directory,
|
||||
recurse => true,
|
||||
purge => true,
|
||||
force => true,
|
||||
ignore => [".svn", ".git", ".gitignore"],
|
||||
source => $version ? {
|
||||
24 => "puppet:///concat/null",
|
||||
default => undef,
|
||||
},
|
||||
notify => Exec["concat_${name}"];
|
||||
|
||||
"${fragdir}/fragments.concat":
|
||||
ensure => present;
|
||||
|
||||
"${fragdir}/${concat_name}":
|
||||
ensure => present;
|
||||
|
||||
$name:
|
||||
source => "${fragdir}/${concat_name}",
|
||||
owner => $owner,
|
||||
group => $group,
|
||||
checksum => md5,
|
||||
mode => $mode,
|
||||
ensure => present,
|
||||
alias => "concat_${name}";
|
||||
}
|
||||
|
||||
exec{"concat_${name}":
|
||||
user => root,
|
||||
group => root,
|
||||
notify => File[$name],
|
||||
subscribe => File[$fragdir],
|
||||
alias => "concat_${fragdir}",
|
||||
require => [ File["/usr/local/bin/concatfragments.sh"], File[$fragdir], File["${fragdir}/fragments"], File["${fragdir}/fragments.concat"] ],
|
||||
unless => "/usr/local/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} -t ${warnflag} ${forceflag}",
|
||||
command => "/usr/local/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} ${warnflag} ${forceflag}",
|
||||
}
|
||||
}
|
36
manifests/setup.pp
Executable file
36
manifests/setup.pp
Executable file
|
@ -0,0 +1,36 @@
|
|||
# Sets up the concat system.
|
||||
#
|
||||
# $concatdir should point to a place where you wish the fragments to
|
||||
# live. This should not be somewhere like /tmp since ideally these files
|
||||
# should not be deleted ever, puppet should always manage them
|
||||
#
|
||||
# $puppetversion should be either 24 or 25 to enable a 24 compatible
|
||||
# mode, in 24 mode you might see phantom notifies this is a side effect
|
||||
# of the method we use to clear the fragments directory.
|
||||
#
|
||||
# The regular expression below will try to figure out your puppet version
|
||||
# but this code will only work in 0.24.8 and newer.
|
||||
#
|
||||
# It also copies out the concatfragments.sh file to /usr/local/bin
|
||||
class concat::setup {
|
||||
$concatdir = "/var/lib/puppet/concat"
|
||||
$majorversion = regsubst($puppetversion, '^[0-9]+[.]([0-9]+)[.][0-9]+$', '\1')
|
||||
|
||||
file{"/usr/local/bin/concatfragments.sh":
|
||||
owner => root,
|
||||
group => root,
|
||||
mode => 755,
|
||||
source => $majorversion ? {
|
||||
24 => "puppet:///concat/concatfragments.sh",
|
||||
default => "puppet:///modules/concat/concatfragments.sh"
|
||||
};
|
||||
|
||||
$concatdir:
|
||||
ensure => directory,
|
||||
owner => root,
|
||||
group => root,
|
||||
mode => 755;
|
||||
}
|
||||
}
|
||||
|
||||
# vi:tabstop=4:expandtab:ai
|
Loading…
Reference in a new issue